<!DOCTYPE html>
<html lang="" xml:lang="">
<head>

  <meta charset="utf-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>第 2 章 基础语法 | 极客R：数据分析之道</title>
  <meta name="description" content="一本极简 R 入门图书" />
  <meta name="generator" content="bookdown 0.19 and GitBook 2.6.7" />

  <meta property="og:title" content="第 2 章 基础语法 | 极客R：数据分析之道" />
  <meta property="og:type" content="book" />
  
  <meta property="og:image" content="cover.png" />
  <meta property="og:description" content="一本极简 R 入门图书" />
  <meta name="github-repo" content="ShixiangWang/geek-r-tutorial" />

  <meta name="twitter:card" content="summary" />
  <meta name="twitter:title" content="第 2 章 基础语法 | 极客R：数据分析之道" />
  
  <meta name="twitter:description" content="一本极简 R 入门图书" />
  <meta name="twitter:image" content="cover.png" />

<meta name="author" content="王诗翔, 生信技能树" />



  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <meta name="apple-mobile-web-app-capable" content="yes" />
  <meta name="apple-mobile-web-app-status-bar-style" content="black" />
  
  
<link rel="prev" href="prepare.html"/>
<link rel="next" href="import.html"/>
<script src="libs/jquery/jquery.min.js"></script>
<link href="libs/gitbook/css/style.css" rel="stylesheet" />
<link href="libs/gitbook/css/plugin-table.css" rel="stylesheet" />
<link href="libs/gitbook/css/plugin-bookdown.css" rel="stylesheet" />
<link href="libs/gitbook/css/plugin-highlight.css" rel="stylesheet" />
<link href="libs/gitbook/css/plugin-search.css" rel="stylesheet" />
<link href="libs/gitbook/css/plugin-fontsettings.css" rel="stylesheet" />
<link href="libs/gitbook/css/plugin-clipboard.css" rel="stylesheet" />











<style type="text/css">
a.sourceLine { display: inline-block; line-height: 1.25; }
a.sourceLine { pointer-events: none; color: inherit; text-decoration: inherit; }
a.sourceLine:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode { white-space: pre; position: relative; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
code.sourceCode { white-space: pre-wrap; }
a.sourceLine { text-indent: -1em; padding-left: 1em; }
}
pre.numberSource a.sourceLine
  { position: relative; left: -4em; }
pre.numberSource a.sourceLine::before
  { content: attr(data-line-number);
    position: relative; left: -1em; text-align: right; vertical-align: baseline;
    border: none; pointer-events: all; display: inline-block;
    -webkit-touch-callout: none; -webkit-user-select: none;
    -khtml-user-select: none; -moz-user-select: none;
    -ms-user-select: none; user-select: none;
    padding: 0 4px; width: 4em;
    color: #aaaaaa;
  }
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
div.sourceCode
  {  }
@media screen {
a.sourceLine::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>

<link rel="stylesheet" href="css/style.css" type="text/css" />
</head>

<body>



  <div class="book without-animation with-summary font-size-2 font-family-1" data-basepath=".">

    <div class="book-summary">
      <nav role="navigation">

<ul class="summary">
<li><a href="./">数据分析之道</a></li>

<li class="divider"></li>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html"><i class="fa fa-check"></i>前言</a><ul>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#内容简介"><i class="fa fa-check"></i>内容简介</a></li>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#许可"><i class="fa fa-check"></i>许可</a></li>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#建议与反馈"><i class="fa fa-check"></i>建议与反馈</a></li>
<li class="chapter" data-level="" data-path="index.html"><a href="index.html#致谢"><i class="fa fa-check"></i>致谢</a></li>
</ul></li>
<li class="chapter" data-level="" data-path="author.html"><a href="author.html"><i class="fa fa-check"></i>作者简介</a></li>
<li class="chapter" data-level="1" data-path="prepare.html"><a href="prepare.html"><i class="fa fa-check"></i><b>1</b> 准备工作</a><ul>
<li class="chapter" data-level="1.1" data-path="prepare.html"><a href="prepare.html#r-的下载和安装"><i class="fa fa-check"></i><b>1.1</b> R 的下载和安装</a></li>
<li class="chapter" data-level="1.2" data-path="prepare.html"><a href="prepare.html#rstudio-的下载和安装"><i class="fa fa-check"></i><b>1.2</b> RStudio 的下载和安装</a></li>
<li class="chapter" data-level="1.3" data-path="prepare.html"><a href="prepare.html#配置可选"><i class="fa fa-check"></i><b>1.3</b> 配置（可选）</a></li>
<li class="chapter" data-level="1.4" data-path="prepare.html"><a href="prepare.html#常见问题与方案"><i class="fa fa-check"></i><b>1.4</b> 常见问题与方案</a><ul>
<li class="chapter" data-level="1.4.1" data-path="prepare.html"><a href="prepare.html#r-在-linux-系统下的安装"><i class="fa fa-check"></i><b>1.4.1</b> R 在 Linux 系统下的安装</a></li>
<li class="chapter" data-level="1.4.2" data-path="prepare.html"><a href="prepare.html#rtools-安装"><i class="fa fa-check"></i><b>1.4.2</b> Rtools 安装</a></li>
<li class="chapter" data-level="1.4.3" data-path="prepare.html"><a href="prepare.html#rstudio-server-安装"><i class="fa fa-check"></i><b>1.4.3</b> RStudio Server 安装</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="2" data-path="base.html"><a href="base.html"><i class="fa fa-check"></i><b>2</b> 基础语法</a><ul>
<li class="chapter" data-level="2.1" data-path="base.html"><a href="base.html#基本数据结构"><i class="fa fa-check"></i><b>2.1</b> 基本数据结构</a><ul>
<li class="chapter" data-level="2.1.1" data-path="base.html"><a href="base.html#向量"><i class="fa fa-check"></i><b>2.1.1</b> 向量</a></li>
<li class="chapter" data-level="2.1.2" data-path="base.html"><a href="base.html#数组与矩阵"><i class="fa fa-check"></i><b>2.1.2</b> 数组与矩阵</a></li>
<li class="chapter" data-level="2.1.3" data-path="base.html"><a href="base.html#数据框"><i class="fa fa-check"></i><b>2.1.3</b> 数据框</a></li>
<li class="chapter" data-level="2.1.4" data-path="base.html"><a href="base.html#列表"><i class="fa fa-check"></i><b>2.1.4</b> 列表</a></li>
</ul></li>
<li class="chapter" data-level="2.2" data-path="base.html"><a href="base.html#控制结构"><i class="fa fa-check"></i><b>2.2</b> 控制结构</a><ul>
<li class="chapter" data-level="2.2.1" data-path="base.html"><a href="base.html#条件控制"><i class="fa fa-check"></i><b>2.2.1</b> 条件控制</a></li>
<li class="chapter" data-level="2.2.2" data-path="base.html"><a href="base.html#循环控制"><i class="fa fa-check"></i><b>2.2.2</b> 循环控制</a></li>
</ul></li>
<li class="chapter" data-level="2.3" data-path="base.html"><a href="base.html#函数与函数式编程"><i class="fa fa-check"></i><b>2.3</b> 函数与函数式编程</a><ul>
<li class="chapter" data-level="2.3.1" data-path="base.html"><a href="base.html#创建和使用函数"><i class="fa fa-check"></i><b>2.3.1</b> 创建和使用函数</a></li>
<li class="chapter" data-level="2.3.2" data-path="base.html"><a href="base.html#作用域"><i class="fa fa-check"></i><b>2.3.2</b> 作用域</a></li>
<li class="chapter" data-level="2.3.3" data-path="base.html"><a href="base.html#任意参数"><i class="fa fa-check"></i><b>2.3.3</b> 任意参数</a></li>
<li class="chapter" data-level="2.3.4" data-path="base.html"><a href="base.html#函数式编程"><i class="fa fa-check"></i><b>2.3.4</b> 函数式编程</a></li>
</ul></li>
<li class="chapter" data-level="2.4" data-path="base.html"><a href="base.html#三方包的安装与加载"><i class="fa fa-check"></i><b>2.4</b> 三方包的安装与加载</a><ul>
<li class="chapter" data-level="2.4.1" data-path="base.html"><a href="base.html#cran"><i class="fa fa-check"></i><b>2.4.1</b> CRAN</a></li>
<li class="chapter" data-level="2.4.2" data-path="base.html"><a href="base.html#bioconductor"><i class="fa fa-check"></i><b>2.4.2</b> Bioconductor</a></li>
<li class="chapter" data-level="2.4.3" data-path="base.html"><a href="base.html#github-等-git-库"><i class="fa fa-check"></i><b>2.4.3</b> GitHub 等 Git 库</a></li>
<li class="chapter" data-level="2.4.4" data-path="base.html"><a href="base.html#包使用"><i class="fa fa-check"></i><b>2.4.4</b> 包使用</a></li>
</ul></li>
<li class="chapter" data-level="2.5" data-path="base.html"><a href="base.html#编程实战roc-曲线计算与绘制"><i class="fa fa-check"></i><b>2.5</b> 编程实战：ROC 曲线计算与绘制</a><ul>
<li class="chapter" data-level="2.5.1" data-path="base.html"><a href="base.html#背景与目标"><i class="fa fa-check"></i><b>2.5.1</b> 背景与目标</a></li>
<li class="chapter" data-level="2.5.2" data-path="base.html"><a href="base.html#代码实现"><i class="fa fa-check"></i><b>2.5.2</b> 代码实现</a></li>
<li class="chapter" data-level="2.5.3" data-path="base.html"><a href="base.html#代码讲解"><i class="fa fa-check"></i><b>2.5.3</b> 代码讲解</a></li>
</ul></li>
<li class="chapter" data-level="2.6" data-path="base.html"><a href="base.html#常见问题与方案-1"><i class="fa fa-check"></i><b>2.6</b> 常见问题与方案</a><ul>
<li class="chapter" data-level="2.6.1" data-path="base.html"><a href="base.html#复数表示"><i class="fa fa-check"></i><b>2.6.1</b> 复数表示</a></li>
<li class="chapter" data-level="2.6.2" data-path="base.html"><a href="base.html#与---的区别"><i class="fa fa-check"></i><b>2.6.2</b> = 与 &lt;- 的区别</a></li>
<li class="chapter" data-level="2.6.3" data-path="base.html"><a href="base.html#显式使用包函数时-与-的区别"><i class="fa fa-check"></i><b>2.6.3</b> 显式使用包函数时 :: 与 ::: 的区别</a></li>
<li class="chapter" data-level="2.6.4" data-path="base.html"><a href="base.html#因子重构"><i class="fa fa-check"></i><b>2.6.4</b> 因子重构</a></li>
<li class="chapter" data-level="2.6.5" data-path="base.html"><a href="base.html#理解-r-计算"><i class="fa fa-check"></i><b>2.6.5</b> 理解 R 计算</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="3" data-path="import.html"><a href="import.html"><i class="fa fa-check"></i><b>3</b> 数据导入</a><ul>
<li class="chapter" data-level="3.1" data-path="import.html"><a href="import.html#符号分隔文件"><i class="fa fa-check"></i><b>3.1</b> 符号分隔文件</a><ul>
<li class="chapter" data-level="3.1.1" data-path="import.html"><a href="import.html#csv"><i class="fa fa-check"></i><b>3.1.1</b> CSV</a></li>
<li class="chapter" data-level="3.1.2" data-path="import.html"><a href="import.html#tsv-与其他-csv-变体"><i class="fa fa-check"></i><b>3.1.2</b> TSV 与其他 CSV 变体</a></li>
</ul></li>
<li class="chapter" data-level="3.2" data-path="import.html"><a href="import.html#excel"><i class="fa fa-check"></i><b>3.2</b> Excel</a></li>
<li class="chapter" data-level="3.3" data-path="import.html"><a href="import.html#json"><i class="fa fa-check"></i><b>3.3</b> JSON</a></li>
<li class="chapter" data-level="3.4" data-path="import.html"><a href="import.html#r-数据文件"><i class="fa fa-check"></i><b>3.4</b> R 数据文件</a><ul>
<li class="chapter" data-level="3.4.1" data-path="import.html"><a href="import.html#rdata"><i class="fa fa-check"></i><b>3.4.1</b> RData</a></li>
<li class="chapter" data-level="3.4.2" data-path="import.html"><a href="import.html#rds"><i class="fa fa-check"></i><b>3.4.2</b> RDS</a></li>
</ul></li>
<li class="chapter" data-level="3.5" data-path="import.html"><a href="import.html#常见问题与方案-2"><i class="fa fa-check"></i><b>3.5</b> 常见问题与方案</a><ul>
<li class="chapter" data-level="3.5.1" data-path="import.html"><a href="import.html#通过键盘和剪贴板载入数据"><i class="fa fa-check"></i><b>3.5.1</b> 通过键盘和剪贴板载入数据</a></li>
<li class="chapter" data-level="3.5.2" data-path="import.html"><a href="import.html#逐行读取数据"><i class="fa fa-check"></i><b>3.5.2</b> 逐行读取数据</a></li>
<li class="chapter" data-level="3.5.3" data-path="import.html"><a href="import.html#读取等宽格式数据"><i class="fa fa-check"></i><b>3.5.3</b> 读取等宽格式数据</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="4" data-path="clean.html"><a href="clean.html"><i class="fa fa-check"></i><b>4</b> 数据清洗</a><ul>
<li class="chapter" data-level="4.1" data-path="clean.html"><a href="clean.html#向量-1"><i class="fa fa-check"></i><b>4.1</b> 向量</a></li>
<li class="chapter" data-level="4.2" data-path="clean.html"><a href="clean.html#单个数据集"><i class="fa fa-check"></i><b>4.2</b> 单个数据集</a><ul>
<li class="chapter" data-level="4.2.1" data-path="clean.html"><a href="clean.html#选择列"><i class="fa fa-check"></i><b>4.2.1</b> 选择列</a></li>
<li class="chapter" data-level="4.2.2" data-path="clean.html"><a href="clean.html#过滤行"><i class="fa fa-check"></i><b>4.2.2</b> 过滤行</a></li>
<li class="chapter" data-level="4.2.3" data-path="clean.html"><a href="clean.html#新增列"><i class="fa fa-check"></i><b>4.2.3</b> 新增列</a></li>
<li class="chapter" data-level="4.2.4" data-path="clean.html"><a href="clean.html#聚合运算"><i class="fa fa-check"></i><b>4.2.4</b> 聚合运算</a></li>
<li class="chapter" data-level="4.2.5" data-path="clean.html"><a href="clean.html#分组计算"><i class="fa fa-check"></i><b>4.2.5</b> 分组计算</a></li>
<li class="chapter" data-level="4.2.6" data-path="clean.html"><a href="clean.html#缺失值填充"><i class="fa fa-check"></i><b>4.2.6</b> 缺失值填充</a></li>
</ul></li>
<li class="chapter" data-level="4.3" data-path="clean.html"><a href="clean.html#两个数据集"><i class="fa fa-check"></i><b>4.3</b> 两个数据集</a></li>
<li class="chapter" data-level="4.4" data-path="clean.html"><a href="clean.html#多个数据集"><i class="fa fa-check"></i><b>4.4</b> 多个数据集</a></li>
<li class="chapter" data-level="4.5" data-path="clean.html"><a href="clean.html#常见问题与方案-3"><i class="fa fa-check"></i><b>4.5</b> 常见问题与方案</a></li>
</ul></li>
<li class="chapter" data-level="5" data-path="visualization.html"><a href="visualization.html"><i class="fa fa-check"></i><b>5</b> 数据可视化</a><ul>
<li class="chapter" data-level="" data-path="visualization.html"><a href="visualization.html#常见问题与方案-4"><i class="fa fa-check"></i>常见问题与方案</a></li>
</ul></li>
<li class="chapter" data-level="6" data-path="model.html"><a href="model.html"><i class="fa fa-check"></i><b>6</b> 统计建模</a><ul>
<li class="chapter" data-level="" data-path="model.html"><a href="model.html#常见问题与方案-5"><i class="fa fa-check"></i>常见问题与方案</a></li>
</ul></li>
<li class="chapter" data-level="7" data-path="report.html"><a href="report.html"><i class="fa fa-check"></i><b>7</b> 结果展示</a><ul>
<li class="chapter" data-level="7.1" data-path="report.html"><a href="report.html#图形"><i class="fa fa-check"></i><b>7.1</b> 图形</a></li>
<li class="chapter" data-level="7.2" data-path="report.html"><a href="report.html#表格"><i class="fa fa-check"></i><b>7.2</b> 表格</a><ul>
<li class="chapter" data-level="7.2.1" data-path="report.html"><a href="report.html#excel-1"><i class="fa fa-check"></i><b>7.2.1</b> Excel</a></li>
</ul></li>
<li class="chapter" data-level="7.3" data-path="report.html"><a href="report.html#rmarkdown"><i class="fa fa-check"></i><b>7.3</b> RMarkdown</a></li>
<li class="chapter" data-level="7.4" data-path="report.html"><a href="report.html#shiny"><i class="fa fa-check"></i><b>7.4</b> Shiny</a></li>
<li class="chapter" data-level="7.5" data-path="report.html"><a href="report.html#常见问题与方案-6"><i class="fa fa-check"></i><b>7.5</b> 常见问题与方案</a><ul>
<li class="chapter" data-level="7.5.1" data-path="report.html"><a href="report.html#export-包集才华与一身"><i class="fa fa-check"></i><b>7.5.1</b> export 包：集才华与一身</a></li>
</ul></li>
</ul></li>
<li class="chapter" data-level="8" data-path="bioapp.html"><a href="bioapp.html"><i class="fa fa-check"></i><b>8</b> 生物信息学应用</a></li>
<li class="appendix"><span><b>附录</b></span></li>
<li class="chapter" data-level="A" data-path="search-table.html"><a href="search-table.html"><i class="fa fa-check"></i><b>A</b> 速查表</a><ul>
<li class="chapter" data-level="A.1" data-path="search-table.html"><a href="search-table.html#数值计算函数"><i class="fa fa-check"></i><b>A.1</b> 数值计算函数</a></li>
<li class="chapter" data-level="A.2" data-path="search-table.html"><a href="search-table.html#模型符号与函数"><i class="fa fa-check"></i><b>A.2</b> 模型符号与函数</a></li>
<li class="chapter" data-level="A.3" data-path="search-table.html"><a href="search-table.html#统计分析与检验"><i class="fa fa-check"></i><b>A.3</b> 统计分析与检验</a></li>
</ul></li>
<li class="chapter" data-level="B" data-path="expand-reading.html"><a href="expand-reading.html"><i class="fa fa-check"></i><b>B</b> 拓展阅读</a><ul>
<li class="chapter" data-level="B.1" data-path="expand-reading.html"><a href="expand-reading.html#生信技能树语雀知识库"><i class="fa fa-check"></i><b>B.1</b> 生信技能树语雀知识库</a></li>
<li class="chapter" data-level="B.2" data-path="expand-reading.html"><a href="expand-reading.html#图书"><i class="fa fa-check"></i><b>B.2</b> 图书</a><ul>
<li class="chapter" data-level="B.2.1" data-path="expand-reading.html"><a href="expand-reading.html#问题与方案"><i class="fa fa-check"></i><b>B.2.1</b> 问题与方案</a></li>
<li class="chapter" data-level="B.2.2" data-path="expand-reading.html"><a href="expand-reading.html#统计建模"><i class="fa fa-check"></i><b>B.2.2</b> 统计建模</a></li>
<li class="chapter" data-level="B.2.3" data-path="expand-reading.html"><a href="expand-reading.html#核心集合"><i class="fa fa-check"></i><b>B.2.3</b> 核心集合</a></li>
<li class="chapter" data-level="B.2.4" data-path="expand-reading.html"><a href="expand-reading.html#生物信息学"><i class="fa fa-check"></i><b>B.2.4</b> 生物信息学</a></li>
<li class="chapter" data-level="B.2.5" data-path="expand-reading.html"><a href="expand-reading.html#r"><i class="fa fa-check"></i><b>B.2.5</b> R</a></li>
</ul></li>
<li class="chapter" data-level="B.3" data-path="expand-reading.html"><a href="expand-reading.html#视频"><i class="fa fa-check"></i><b>B.3</b> 视频</a></li>
<li class="chapter" data-level="B.4" data-path="expand-reading.html"><a href="expand-reading.html#公众号"><i class="fa fa-check"></i><b>B.4</b> 公众号</a></li>
<li class="chapter" data-level="B.5" data-path="expand-reading.html"><a href="expand-reading.html#其他资料"><i class="fa fa-check"></i><b>B.5</b> 其他资料</a></li>
</ul></li>
<li class="chapter" data-level="" data-path="references.html"><a href="references.html"><i class="fa fa-check"></i>参考文献</a></li>
</ul>

      </nav>
    </div>

    <div class="book-body">
      <div class="body-inner">
        <div class="book-header" role="navigation">
          <h1>
            <i class="fa fa-circle-o-notch fa-spin"></i><a href="./">极客R：数据分析之道</a>
          </h1>
        </div>

        <div class="page-wrapper" tabindex="-1" role="main">
          <div class="page-inner">

            <section class="normal" id="section-">
<div id="base" class="section level1">
<h1><span class="header-section-number">第 2 章</span> 基础语法</h1>
<p>“程序 = 算法 + 数据结构”，<strong>数据结构</strong>是信息的载体，而<strong>算法</strong>是完成任务所需要的步骤。两者的构造和使用方法形成了编程语言独特的语法。本章先介绍 R 的基本数据结构，然后介绍条件和循环控制，接着介绍函数的创建与拓展包的使用，最后通过编程实战来实践和掌握本章涉及的知识点。</p>
<div id="基本数据结构" class="section level2">
<h2><span class="header-section-number">2.1</span> 基本数据结构</h2>
<p>为了表示现实世界的信息，各类编程语言常包含 3 种基本的数据类型：<strong>数值型</strong>，包括整数和浮点数；<strong>字符型</strong>，表示文本信息；<strong>逻辑型</strong>，也常称为布尔值，表示是非判断，如对与错，是与否。在 R 中，除了这些基本数据类型的实现，为了方便计算工作，R 本身还包含了矩阵、数据框和列表等复杂的数据类型，以支持表示各类常用的数据。</p>
<div id="向量" class="section level3">
<h3><span class="header-section-number">2.1.1</span> 向量</h3>
<p>在 R 中，数据运算常通过向量的形式进行。<strong>向量</strong>是一组同质的信息，如 20 个数字、30 个字符串（与数学术语中的向量类似，但不等同）。单一的信息在此被称为<strong>元素</strong>。<strong>标量</strong>可以看作元素数量为 1 的向量。</p>
<p>接下来我们通过向量元素的数据类型来实际地了解和操作它。</p>
<div id="数值" class="section level4">
<h4><span class="header-section-number">2.1.1.1</span> 数值</h4>
<p>数值应该可以说是最常用的信息表现形式，如人的身高、年龄。在 R 中使用小学学到的阿拉伯表示法即可创建数值，如圆周率 <span class="math inline">\(\pi\)</span>：</p>
<div class="sourceCode" id="cb17"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb17-1" data-line-number="1"><span class="fl">3.14</span></a>
<a class="sourceLine" id="cb17-2" data-line-number="2"><span class="co">#&gt; [1] 3.14</span></a></code></pre></div>
<blockquote>
<p>此处 <code>#&gt;</code> 后显示 R 运行代码后的返回结果，<code>[1]</code> 是结果的索引，以辅助用户观测，这里表示结果的第 1 个值是 3.14。</p>
</blockquote>
<p><code>typeof()</code> 与 <code>class()</code> 是两个对于初学者非常有用的函数，它们可以返回数据的类型信息。</p>
<div class="sourceCode" id="cb18"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb18-1" data-line-number="1"><span class="kw">typeof</span>(<span class="fl">3.14</span>)</a>
<a class="sourceLine" id="cb18-2" data-line-number="2"><span class="co">#&gt; [1] &quot;double&quot;</span></a>
<a class="sourceLine" id="cb18-3" data-line-number="3"><span class="kw">class</span>(<span class="fl">3.14</span>)</a>
<a class="sourceLine" id="cb18-4" data-line-number="4"><span class="co">#&gt; [1] &quot;numeric&quot;</span></a></code></pre></div>
<p>在 R 中不需要像其他语言一样区分数值的精度信息，<code>typeof()</code> 返回结果为 <code>double</code> 提示该值是一个浮点数。</p>
<p>在 R 中，任何所见的事物皆为<strong>对象</strong>，<code>class()</code> 返回对象的类信息，此处是 <code>numeric</code>（数值）。</p>
<p>我们再来看看如何在 R 中表示整数。借助上述两个工具函数，我们不难发现下面的代码与想象不同。</p>
<div class="sourceCode" id="cb19"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb19-1" data-line-number="1"><span class="dv">3</span></a>
<a class="sourceLine" id="cb19-2" data-line-number="2"><span class="co">#&gt; [1] 3</span></a>
<a class="sourceLine" id="cb19-3" data-line-number="3"></a>
<a class="sourceLine" id="cb19-4" data-line-number="4"><span class="kw">typeof</span>(<span class="dv">3</span>)</a>
<a class="sourceLine" id="cb19-5" data-line-number="5"><span class="co">#&gt; [1] &quot;double&quot;</span></a>
<a class="sourceLine" id="cb19-6" data-line-number="6"><span class="kw">class</span>(<span class="dv">3</span>)</a>
<a class="sourceLine" id="cb19-7" data-line-number="7"><span class="co">#&gt; [1] &quot;numeric&quot;</span></a></code></pre></div>
<p><code>typeof()</code> 与 <code>class()</code> 对于 3 的返回结果与 3.14 完全相同！这是因为即便只输入 3，R 也将其作为浮点数对待。</p>
<p>我们可以利用 <code>identical()</code> 函数或 <code>is.integer()</code> 函数进行检查：</p>
<div class="sourceCode" id="cb20"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb20-1" data-line-number="1"><span class="kw">identical</span>(<span class="dv">3</span>, <span class="fl">3.0</span>)</a>
<a class="sourceLine" id="cb20-2" data-line-number="2"><span class="co">#&gt; [1] TRUE</span></a>
<a class="sourceLine" id="cb20-3" data-line-number="3"></a>
<a class="sourceLine" id="cb20-4" data-line-number="4"><span class="kw">is.integer</span>(<span class="dv">3</span>)</a>
<a class="sourceLine" id="cb20-5" data-line-number="5"><span class="co">#&gt; [1] FALSE</span></a></code></pre></div>
<p>返回的结果是后面将介绍的逻辑值，<code>TRUE</code> 表示对、<code>FALSE</code> 表示错。因此可以判断 <code>3</code> 并不是整数。</p>
<p>正确的整数表示方法需要在数字后加 <code>L</code> 后缀，如 <code>3L</code>。</p>
<div class="sourceCode" id="cb21"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb21-1" data-line-number="1"><span class="kw">is.integer</span>(3L)</a>
<a class="sourceLine" id="cb21-2" data-line-number="2"><span class="co">#&gt; [1] TRUE</span></a>
<a class="sourceLine" id="cb21-3" data-line-number="3"></a>
<a class="sourceLine" id="cb21-4" data-line-number="4"><span class="kw">identical</span>(3L, <span class="dv">3</span>)</a>
<a class="sourceLine" id="cb21-5" data-line-number="5"><span class="co">#&gt; [1] FALSE</span></a></code></pre></div>
<p><code>is.integer()</code> 函数隶属于 <code>is.xxx()</code> 家族，该函数家族用于辅助判断对象是否属于某一类型。读者在 RStudio 中输入 <code>is.</code> 后 RStudio 将智能提示有哪些函数的名字以 <code>is.</code> 开头。</p>
<p>浮点数和整数都是数值，所以下面的代码都会返回 <code>TRUE</code>：</p>
<div class="sourceCode" id="cb22"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb22-1" data-line-number="1"><span class="kw">is.numeric</span>(<span class="fl">3.14</span>)</a>
<a class="sourceLine" id="cb22-2" data-line-number="2"><span class="co">#&gt; [1] TRUE</span></a>
<a class="sourceLine" id="cb22-3" data-line-number="3"><span class="kw">is.numeric</span>(3L)</a>
<a class="sourceLine" id="cb22-4" data-line-number="4"><span class="co">#&gt; [1] TRUE</span></a></code></pre></div>
<p>现实中的数据常成组出现，例如，一组学生的身高。R 使用 <code>c()</code> 函数（<code>c</code> 为 <code>combine</code> 的缩写）对数据进行组合：</p>
<div class="sourceCode" id="cb23"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb23-1" data-line-number="1"><span class="kw">c</span>(<span class="fl">1.70</span>, <span class="fl">1.72</span>, <span class="fl">1.80</span>, <span class="fl">1.66</span>, <span class="fl">1.65</span>, <span class="fl">1.88</span>)</a>
<a class="sourceLine" id="cb23-2" data-line-number="2"><span class="co">#&gt; [1] 1.70 1.72 1.80 1.66 1.65 1.88</span></a></code></pre></div>
<p>这样我们就有了一组身高数据。</p>
<p>利用 R 自带的 <code>mean()</code> 和 <code>sd()</code> 还是我们可以轻易求取这组数据的均值和标准差：</p>
<div class="sourceCode" id="cb24"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb24-1" data-line-number="1"><span class="co"># 均值</span></a>
<a class="sourceLine" id="cb24-2" data-line-number="2"><span class="kw">mean</span>(<span class="kw">c</span>(<span class="fl">1.70</span>, <span class="fl">1.72</span>, <span class="fl">1.80</span>, <span class="fl">1.66</span>, <span class="fl">1.65</span>, <span class="fl">1.88</span>))</a>
<a class="sourceLine" id="cb24-3" data-line-number="3"><span class="co">#&gt; [1] 1.735</span></a>
<a class="sourceLine" id="cb24-4" data-line-number="4"><span class="co"># 标准差</span></a>
<a class="sourceLine" id="cb24-5" data-line-number="5"><span class="kw">sd</span>(<span class="kw">c</span>(<span class="fl">1.70</span>, <span class="fl">1.72</span>, <span class="fl">1.80</span>, <span class="fl">1.66</span>, <span class="fl">1.65</span>, <span class="fl">1.88</span>))</a>
<a class="sourceLine" id="cb24-6" data-line-number="6"><span class="co">#&gt; [1] 0.08894</span></a></code></pre></div>
<p>上面我们计算时我们重复输入了身高数据，如果在输入时发生了小小的意外，如计算标准差时将 <code>1.65</code> 写成了 <code>1.66</code>，那么我们分析得就不是同一组数据了！虽然说在上述的简单计算不太可能发生这种情况，但如果存在 100 甚至 1000 个数据的重复输入，依靠人眼判断几乎是必然出错的。</p>
<p>一个解决办法是依赖系统自带的复制粘贴机制，但如果一组数据被上百次重复使用，这种办法也不实际。</p>
<p>正确的解决办法是引入一个符号（Symbol），用该符号<strong>指代</strong>一组数据，然后每次需要使用该数据时，使用符号代替即可。符号在编程语言中也常被称为<strong>变量</strong>，后面我们统一使用该术语。</p>
<p>上述代码块改写为：</p>
<div class="sourceCode" id="cb25"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb25-1" data-line-number="1">heights &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="fl">1.70</span>, <span class="fl">1.72</span>, <span class="fl">1.80</span>, <span class="fl">1.66</span>, <span class="fl">1.65</span>, <span class="fl">1.88</span>)</a>
<a class="sourceLine" id="cb25-2" data-line-number="2"><span class="kw">mean</span>(heights)</a>
<a class="sourceLine" id="cb25-3" data-line-number="3"><span class="co">#&gt; [1] 1.735</span></a>
<a class="sourceLine" id="cb25-4" data-line-number="4"><span class="kw">sd</span>(heights)</a>
<a class="sourceLine" id="cb25-5" data-line-number="5"><span class="co">#&gt; [1] 0.08894</span></a></code></pre></div>
<p><code>&lt;-</code> 符号在 R 中称为赋值符号，我们可以将它看作数据的流动方向，这样更方便理解，我们不难猜测到 <code>-&gt;</code> 的写法也是有效的：</p>
<div class="sourceCode" id="cb26"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb26-1" data-line-number="1"><span class="kw">c</span>(<span class="fl">1.70</span>, <span class="fl">1.72</span>, <span class="fl">1.80</span>, <span class="fl">1.66</span>, <span class="fl">1.65</span>, <span class="fl">1.88</span>) -&gt;<span class="st"> </span>heights2</a>
<a class="sourceLine" id="cb26-2" data-line-number="2">heights2</a>
<a class="sourceLine" id="cb26-3" data-line-number="3"><span class="co">#&gt; [1] 1.70 1.72 1.80 1.66 1.65 1.88</span></a></code></pre></div>
<p>但通常以 <code>&lt;-</code> 的写法为主。</p>
<p>另外，<code>=</code> 符号与 <code>&lt;-</code> 有基本相同的含义，但不常用。如果读者有其他编程语言经验，也可以使用它作为常用赋值符号。两者的区别见本章【<strong>常见问题与方案</strong>】一节。</p>
<p>R 中变量的命名有一些限制，最重要的就是不要以数字开头：</p>
<div class="sourceCode" id="cb27"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb27-1" data-line-number="1">3ab =<span class="st"> </span><span class="dv">3</span></a>
<a class="sourceLine" id="cb27-2" data-line-number="2"><span class="co">#&gt; Error: &lt;text&gt;:1:2: unexpected symbol</span></a>
<a class="sourceLine" id="cb27-3" data-line-number="3"><span class="co">#&gt; 1: 3ab</span></a>
<a class="sourceLine" id="cb27-4" data-line-number="4"><span class="co">#&gt;      ^</span></a></code></pre></div>
<p>变量命名有 2 点建议：</p>
<ol style="list-style-type: decimal">
<li>对于一些临时使用的变量，以简单为主，如 <code>i</code>、<code>j</code>、<code>k</code> 等。</li>
<li>与数据相关的命名，建议与其信息一致，如上面的代码我使用了 <code>heights</code>，不然在没有注释的情况下，代码的阅读者无法快速理解你写的程序。</li>
</ol>
<p>另外，<strong>长变量</strong>的命名通常有 2 个推荐的规则：</p>
<ol style="list-style-type: decimal">
<li>骆驼法</li>
</ol>
<p>以学生身高数据为例，可以写为 <code>studentHeights</code>，它遵循 <code>aBcDeF</code> 这样的构造方式。</p>
<ol start="2" style="list-style-type: decimal">
<li>蛇形</li>
</ol>
<p>以下划线作为分隔符，写为 <code>student_heights</code>。</p>
<p>两种写法在 R 中都很常用，读者选择一种即可，<strong>重点在于一个 R 脚本中应当保持变量名命名风格的一致</strong>。</p>
<p>在了解向量和变量后，我们再来学习下向量的计算方式。</p>
<p>假设我们有两组数据，分别以变量 <code>a</code> 和 <code>b</code> 存储：</p>
<div class="sourceCode" id="cb28"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb28-1" data-line-number="1">a &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)</a>
<a class="sourceLine" id="cb28-2" data-line-number="2">b &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>)</a></code></pre></div>
<p>我们将其堆叠到一起，如图 <a href="base.html#fig:vector-construction">2.1</a>：</p>
<div class="figure" style="text-align: center"><span id="fig:vector-construction"></span>
<img src="bookdown_files/figure-html/vector-construction-1.png" alt="向量的直观展示" width="384" />
<p class="caption">
图 2.1: 向量的直观展示
</p>
</div>
<p>当我们将 <code>a</code> 与 <code>b</code> 相加，结果是什么呢？</p>
<div class="sourceCode" id="cb29"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb29-1" data-line-number="1">a <span class="op">+</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb29-2" data-line-number="2"><span class="co">#&gt; [1] 5 7 9</span></a></code></pre></div>
<p>两个向量之和是向量元素一一相加组成的向量。如果向量的元素不相同，结果又是如何呢？</p>
<p>我们将 <code>a</code> 与 <code>4</code> 相加看一看，此时向量堆叠如图 <a href="base.html#fig:vector-add">2.2</a> 所示：</p>
<div class="figure" style="text-align: center"><span id="fig:vector-add"></span>
<img src="bookdown_files/figure-html/vector-add-1.png" alt="向量不等长图示" width="384" />
<p class="caption">
图 2.2: 向量不等长图示
</p>
</div>
<div class="sourceCode" id="cb30"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb30-1" data-line-number="1">a <span class="op">+</span><span class="st"> </span><span class="dv">4</span></a>
<a class="sourceLine" id="cb30-2" data-line-number="2"><span class="co">#&gt; [1] 5 6 7</span></a></code></pre></div>
<p>上述结果与 <code>a + c(4, 4, 4)</code> 相同：</p>
<div class="sourceCode" id="cb31"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb31-1" data-line-number="1">a <span class="op">+</span><span class="st"> </span><span class="kw">c</span>(<span class="dv">4</span>, <span class="dv">4</span>, <span class="dv">4</span>)</a>
<a class="sourceLine" id="cb31-2" data-line-number="2"><span class="co">#&gt; [1] 5 6 7</span></a></code></pre></div>
<p>因此，如果向量不等长时，短向量会通过重复与长向量先对齐（如图 <a href="base.html#fig:vector-align">2.3</a>），然后再相加。</p>
<div class="figure" style="text-align: center"><span id="fig:vector-align"></span>
<img src="bookdown_files/figure-html/vector-align-1.png" alt="向量对齐" width="384" />
<p class="caption">
图 2.3: 向量对齐
</p>
</div>
<p>注意，此过程中，长向量会保持不变，如果出现短向量重复后无法对齐的情况，多余的部分将被扔掉，R 返回结果的同时会抛出一个警告信息。</p>
<div class="sourceCode" id="cb32"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb32-1" data-line-number="1"><span class="kw">c</span>(<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>) <span class="op">+</span><span class="st"> </span><span class="kw">c</span>(<span class="dv">4</span>, <span class="dv">5</span>)</a>
<a class="sourceLine" id="cb32-2" data-line-number="2"><span class="co">#&gt; Warning in c(1, 2, 3) + c(4, 5): 长的对象长度不是短的对</span></a>
<a class="sourceLine" id="cb32-3" data-line-number="3"><span class="co">#&gt; 象长度的整倍数</span></a>
<a class="sourceLine" id="cb32-4" data-line-number="4"><span class="co">#&gt; [1] 5 7 7</span></a>
<a class="sourceLine" id="cb32-5" data-line-number="5"><span class="co"># 上面的加法等价于 c(1, 2, 3) + c(4, 5, 4)</span></a></code></pre></div>
<p>整个过程称为<strong>向量化运算</strong>。除了加法，其他任何向量（几何）运算方式都相同。</p>
<div class="sourceCode" id="cb33"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb33-1" data-line-number="1"><span class="co"># 想减</span></a>
<a class="sourceLine" id="cb33-2" data-line-number="2">a <span class="op">-</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb33-3" data-line-number="3"><span class="co">#&gt; [1] -3 -3 -3</span></a>
<a class="sourceLine" id="cb33-4" data-line-number="4"><span class="co"># 相除</span></a>
<a class="sourceLine" id="cb33-5" data-line-number="5">a <span class="op">/</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb33-6" data-line-number="6"><span class="co">#&gt; [1] 0.25 0.40 0.50</span></a>
<a class="sourceLine" id="cb33-7" data-line-number="7"><span class="co"># 相乘</span></a>
<a class="sourceLine" id="cb33-8" data-line-number="8">a <span class="op">*</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb33-9" data-line-number="9"><span class="co">#&gt; [1]  4 10 18</span></a>
<a class="sourceLine" id="cb33-10" data-line-number="10"><span class="co"># 整除</span></a>
<a class="sourceLine" id="cb33-11" data-line-number="11">a <span class="op">%/%</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb33-12" data-line-number="12"><span class="co">#&gt; [1] 0 0 0</span></a>
<a class="sourceLine" id="cb33-13" data-line-number="13"><span class="co"># 取余数</span></a>
<a class="sourceLine" id="cb33-14" data-line-number="14">a <span class="op">%%</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb33-15" data-line-number="15"><span class="co">#&gt; [1] 1 2 3</span></a>
<a class="sourceLine" id="cb33-16" data-line-number="16"><span class="co"># 平方</span></a>
<a class="sourceLine" id="cb33-17" data-line-number="17">a <span class="op">^</span><span class="st"> </span><span class="dv">2</span></a>
<a class="sourceLine" id="cb33-18" data-line-number="18"><span class="co">#&gt; [1] 1 4 9</span></a>
<a class="sourceLine" id="cb33-19" data-line-number="19"><span class="co"># 取对数</span></a>
<a class="sourceLine" id="cb33-20" data-line-number="20"><span class="kw">log</span>(a, <span class="dt">base =</span> <span class="dv">2</span>)</a>
<a class="sourceLine" id="cb33-21" data-line-number="21"><span class="co">#&gt; [1] 0.000 1.000 1.585</span></a></code></pre></div>
<p><strong>向量化运算</strong>的本质是成对的向量元素运算操作。这个特性让 R 在处理数据时非常方便，无论向量元素的个数是多少，在运算时我们都可以将其作为标量对待。</p>
<p>例如，计算数据 <code>heights</code> 的均值和标准差，这里我们直接通过公式而不是 R 自带的函数进行计算：</p>
<p><span class="math display">\[
\mu = \frac{\sum x_i}{n}
\]</span></p>
<p><span class="math display">\[
sd = \sqrt\frac{\sum(x_i - \mu)^2}{n - 1}
\]</span></p>
<blockquote>
<p><code>sd</code> 的计算中使用的是 <code>n-1</code> 而不是 <code>n</code> 的原因是我们计算的是<strong>样本</strong>标准差。</p>
</blockquote>
<p>实际操作如下：</p>
<div class="sourceCode" id="cb34"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb34-1" data-line-number="1"><span class="co"># 先计算均值</span></a>
<a class="sourceLine" id="cb34-2" data-line-number="2">heightsMean &lt;-<span class="st"> </span><span class="kw">sum</span>(heights) <span class="op">/</span><span class="st"> </span><span class="kw">length</span>(heights)</a>
<a class="sourceLine" id="cb34-3" data-line-number="3">heightsMean</a>
<a class="sourceLine" id="cb34-4" data-line-number="4"><span class="co">#&gt; [1] 1.735</span></a>
<a class="sourceLine" id="cb34-5" data-line-number="5"><span class="co"># 计算标准差</span></a>
<a class="sourceLine" id="cb34-6" data-line-number="6">heightsSD &lt;-<span class="st"> </span><span class="kw">sqrt</span>( <span class="kw">sum</span>( (heights <span class="op">-</span><span class="st"> </span>heightsMean)<span class="op">^</span><span class="st"> </span><span class="dv">2</span>) <span class="op">/</span><span class="st"> </span>(<span class="kw">length</span>(heights) <span class="op">-</span><span class="st"> </span><span class="dv">1</span>) )</a>
<a class="sourceLine" id="cb34-7" data-line-number="7">heightsSD</a>
<a class="sourceLine" id="cb34-8" data-line-number="8"><span class="co">#&gt; [1] 0.08894</span></a></code></pre></div>
<p>将结果与 R 函数计算结果对比：</p>
<div class="sourceCode" id="cb35"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb35-1" data-line-number="1"><span class="kw">mean</span>(heights)</a>
<a class="sourceLine" id="cb35-2" data-line-number="2"><span class="co">#&gt; [1] 1.735</span></a>
<a class="sourceLine" id="cb35-3" data-line-number="3"><span class="kw">sd</span>(heights)</a>
<a class="sourceLine" id="cb35-4" data-line-number="4"><span class="co">#&gt; [1] 0.08894</span></a></code></pre></div>
<p>注意，上述我们使用了 R 的一些其他工具函数，<code>length()</code> 用来获取向量的长度，而 <code>sum()</code> 用来获取向量之和，<code>sqrt()</code> 用来计算开方。</p>
<p>初学者可能对于计算中使用的一些计算函数感到陌生，这是<strong>非常非常非常正常</strong>的，我个人也无法记得所有 R 提供的函数，编程是一门实践课程，读者需要通过使用去熟悉，而无法通过死记硬背掌握。在想要使用自己不知道的函数时，这里有几点建议：</p>
<ol style="list-style-type: decimal">
<li>猜测函数名。R 的函数命名方式是有规律可循的，且大体有对应的英文含义，读者不妨先尝试猜一猜函数名，看看是否真的有。</li>
<li>使用 R 的文档系统。R 的文档系统非常丰富，读者可以在 R 控制台 <code>?numeric</code> 来获取关于 <code>numeric</code> 的相关信息。而 <code>??numeric</code> 可以进行更为深度的搜索。学会读和理解函数文档是掌握 R 必备的技能。</li>
<li>使用搜索引擎。（初学者）遇到的问题基本都会有人遇到，R 的用户众多，各个博客和论坛都记录了关于 R 的使用和问题讨论，在上述 2 点无法解决问题时，读者不妨多使用搜索引擎查找相关资料。</li>
</ol>
<p>这一小节我们通过数值数据作为对象学习了一些重要的 R 基础概念和操作。接下来我们将这些知识拓展到其他基础数据类型中就相对容易多了。</p>
</div>
<div id="字符串" class="section level4">
<h4><span class="header-section-number">2.1.1.2</span> 字符串</h4>
<p>日常数据处理任务中除了常见的数值型数据，文本数据也比较常用。例如，表示性别是“男”或“女”，教育程度是“中学”还是“大学”。</p>
<p>在 R 中，并不能直接通过输入非数值的字符创建字符串：</p>
<div class="sourceCode" id="cb36"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb36-1" data-line-number="1">男</a>
<a class="sourceLine" id="cb36-2" data-line-number="2"><span class="co">#&gt; Error in eval(expr, envir, enclos): 找不到对象&#39;男&#39;</span></a></code></pre></div>
<p>文本数据需要通过单引号 <code>''</code> 或双引号 <code>&quot;&quot;</code> 引号括起来，这样就可以创建字符串了：</p>
<div class="sourceCode" id="cb37"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb37-1" data-line-number="1"><span class="st">&#39;男&#39;</span></a>
<a class="sourceLine" id="cb37-2" data-line-number="2"><span class="co">#&gt; [1] &quot;男&quot;</span></a>
<a class="sourceLine" id="cb37-3" data-line-number="3"><span class="st">&quot;女&quot;</span></a>
<a class="sourceLine" id="cb37-4" data-line-number="4"><span class="co">#&gt; [1] &quot;女&quot;</span></a></code></pre></div>
<div class="sourceCode" id="cb38"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb38-1" data-line-number="1"><span class="kw">typeof</span>(<span class="st">&quot;abcde&quot;</span>)</a>
<a class="sourceLine" id="cb38-2" data-line-number="2"><span class="co">#&gt; [1] &quot;character&quot;</span></a>
<a class="sourceLine" id="cb38-3" data-line-number="3"><span class="kw">class</span>(<span class="st">&quot;abcde&quot;</span>)</a>
<a class="sourceLine" id="cb38-4" data-line-number="4"><span class="co">#&gt; [1] &quot;character&quot;</span></a></code></pre></div>
<p>单双引号可以通过嵌套以实现单引号或者双引号的输出：</p>
<div class="sourceCode" id="cb39"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb39-1" data-line-number="1"><span class="st">&#39;&quot;abcde&quot;&#39;</span></a>
<a class="sourceLine" id="cb39-2" data-line-number="2"><span class="co">#&gt; [1] &quot;\&quot;abcde\&quot;&quot;</span></a>
<a class="sourceLine" id="cb39-3" data-line-number="3"><span class="st">&quot;&#39;abcde&quot;</span></a>
<a class="sourceLine" id="cb39-4" data-line-number="4"><span class="co">#&gt; [1] &quot;&#39;abcde&quot;</span></a></code></pre></div>
<p>由于 R 的底层实现只有双引号，所以 <code>'&quot;abcde&quot;'</code> 输出中的 <code>&quot;</code> 带有转义符号 <code>\</code>（反斜杠）。读者可以利用转义符号完成对引号（或其他一些特殊符号）的输出操作。</p>
<div class="sourceCode" id="cb40"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb40-1" data-line-number="1"><span class="st">&#39;</span><span class="ch">\&#39;</span><span class="st">abc&#39;</span>    <span class="co"># a 前面的单引号被转义了，&#39;&#39;abc&#39; 则是错误的写法</span></a>
<a class="sourceLine" id="cb40-2" data-line-number="2"><span class="co">#&gt; [1] &quot;&#39;abc&quot;</span></a>
<a class="sourceLine" id="cb40-3" data-line-number="3"><span class="st">&quot;</span><span class="ch">\&quot;\&#39;</span><span class="st">abc&quot;</span>  <span class="co"># 参照上面进行理解，试试运行 &quot;&quot;&#39;abc&quot;，你会观察到什么现象？为什么？</span></a>
<a class="sourceLine" id="cb40-4" data-line-number="4"><span class="co">#&gt; [1] &quot;\&quot;&#39;abc&quot;</span></a></code></pre></div>
<p>函数 <code>nchar()</code> 常用于获取字符串中字符的个数：</p>
<div class="sourceCode" id="cb41"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb41-1" data-line-number="1"><span class="kw">nchar</span>(<span class="st">&quot;abcde&quot;</span>)</a>
<a class="sourceLine" id="cb41-2" data-line-number="2"><span class="co">#&gt; [1] 5</span></a></code></pre></div>
<p>注意，这与获取字符串向量的元素个数是不同的：</p>
<div class="sourceCode" id="cb42"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb42-1" data-line-number="1">abc &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;abcde&quot;</span>, <span class="st">&quot;f&quot;</span>, <span class="st">&quot;g&quot;</span>)</a>
<a class="sourceLine" id="cb42-2" data-line-number="2"><span class="kw">length</span>(abc)</a>
<a class="sourceLine" id="cb42-3" data-line-number="3"><span class="co">#&gt; [1] 3</span></a>
<a class="sourceLine" id="cb42-4" data-line-number="4"><span class="kw">nchar</span>(abc)</a>
<a class="sourceLine" id="cb42-5" data-line-number="5"><span class="co">#&gt; [1] 5 1 1</span></a></code></pre></div>
<p>字符串常涉及集合操作，如交集、并集、差集:</p>
<div class="sourceCode" id="cb43"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb43-1" data-line-number="1"><span class="co"># 交集</span></a>
<a class="sourceLine" id="cb43-2" data-line-number="2"><span class="kw">intersect</span>(<span class="kw">c</span>(<span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;c&quot;</span>),</a>
<a class="sourceLine" id="cb43-3" data-line-number="3">          <span class="kw">c</span>(<span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;d&quot;</span>))</a>
<a class="sourceLine" id="cb43-4" data-line-number="4"><span class="co">#&gt; [1] &quot;a&quot; &quot;b&quot;</span></a>
<a class="sourceLine" id="cb43-5" data-line-number="5"><span class="co"># 并集</span></a>
<a class="sourceLine" id="cb43-6" data-line-number="6"><span class="kw">union</span>(<span class="kw">c</span>(<span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;c&quot;</span>),</a>
<a class="sourceLine" id="cb43-7" data-line-number="7">      <span class="kw">c</span>(<span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;d&quot;</span>))</a>
<a class="sourceLine" id="cb43-8" data-line-number="8"><span class="co">#&gt; [1] &quot;a&quot; &quot;b&quot; &quot;c&quot; &quot;d&quot;</span></a>
<a class="sourceLine" id="cb43-9" data-line-number="9"><span class="co"># 差集</span></a>
<a class="sourceLine" id="cb43-10" data-line-number="10"><span class="kw">setdiff</span>(<span class="kw">c</span>(<span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;c&quot;</span>),</a>
<a class="sourceLine" id="cb43-11" data-line-number="11">        <span class="kw">c</span>(<span class="st">&quot;a&quot;</span>, <span class="st">&quot;b&quot;</span>, <span class="st">&quot;d&quot;</span>))</a>
<a class="sourceLine" id="cb43-12" data-line-number="12"><span class="co">#&gt; [1] &quot;c&quot;</span></a></code></pre></div>
<p>注意，集合操作同样适用于其他数据类型，读者不妨试一试。</p>
</div>
<div id="因子" class="section level4">
<h4><span class="header-section-number">2.1.1.3</span> 因子</h4>
<p>因子是另类的字符串，它引入了水平信息，更有利于保存和展示分类的文本数据，创建方式如下：</p>
<div class="sourceCode" id="cb44"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb44-1" data-line-number="1">sex &lt;-<span class="st"> </span><span class="kw">factor</span>(<span class="kw">c</span>(<span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Male&quot;</span>))</a>
<a class="sourceLine" id="cb44-2" data-line-number="2">sex</a>
<a class="sourceLine" id="cb44-3" data-line-number="3"><span class="co">#&gt; [1] Male   Female Female Male   Male  </span></a>
<a class="sourceLine" id="cb44-4" data-line-number="4"><span class="co">#&gt; Levels: Female Male</span></a></code></pre></div>
<p>上述结果除了打印向量本身的元素，还输出了变量 <code>sex</code> 的水平信息。水平信息可以通过 <code>levels()</code> 函数获取。</p>
<div class="sourceCode" id="cb45"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb45-1" data-line-number="1"><span class="kw">levels</span>(sex)</a>
<a class="sourceLine" id="cb45-2" data-line-number="2"><span class="co">#&gt; [1] &quot;Female&quot; &quot;Male&quot;</span></a></code></pre></div>
<p>重命名因子水平，可以完成对应所有元素的修改：</p>
<div class="sourceCode" id="cb46"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb46-1" data-line-number="1"><span class="kw">levels</span>(sex) &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;Female&quot;</span>, <span class="st">&quot;男的&quot;</span>)</a>
<a class="sourceLine" id="cb46-2" data-line-number="2">sex</a>
<a class="sourceLine" id="cb46-3" data-line-number="3"><span class="co">#&gt; [1] 男的   Female Female 男的   男的  </span></a>
<a class="sourceLine" id="cb46-4" data-line-number="4"><span class="co">#&gt; Levels: Female 男的</span></a></code></pre></div>
<p>水平可以在创建因子时指定，如果一些分类没有对应的水平，将被转换为 <code>NA</code>（Not Available 的缩写），<code>NA</code> 是 R 中比较特殊的一个值，表示数据未知的状态。</p>
<div class="sourceCode" id="cb47"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb47-1" data-line-number="1"><span class="kw">factor</span>(<span class="kw">c</span>(<span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Male&quot;</span>, <span class="st">&quot;M&quot;</span>, <span class="st">&quot;M&quot;</span>), <span class="dt">levels =</span> <span class="kw">c</span>(<span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Female&quot;</span>))</a>
<a class="sourceLine" id="cb47-2" data-line-number="2"><span class="co">#&gt; [1] Male   Female Female Male   Male   &lt;NA&gt;   &lt;NA&gt;  </span></a>
<a class="sourceLine" id="cb47-3" data-line-number="3"><span class="co">#&gt; Levels: Male Female</span></a></code></pre></div>
<p>除了水平，我们还可以为分类添加标签以展示某一分类对应的具体信息：</p>
<div class="sourceCode" id="cb48"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb48-1" data-line-number="1"><span class="kw">factor</span>(<span class="kw">c</span>(<span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Male&quot;</span>, <span class="st">&quot;M&quot;</span>, <span class="st">&quot;M&quot;</span>), </a>
<a class="sourceLine" id="cb48-2" data-line-number="2">       <span class="dt">levels =</span> <span class="kw">c</span>(<span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Female&quot;</span>),</a>
<a class="sourceLine" id="cb48-3" data-line-number="3">       <span class="dt">labels =</span> <span class="kw">c</span>(<span class="st">&quot;性别：男&quot;</span>, <span class="st">&quot;性别：女&quot;</span>))</a>
<a class="sourceLine" id="cb48-4" data-line-number="4"><span class="co">#&gt; [1] 性别：男 性别：女 性别：女 性别：男 性别：男</span></a>
<a class="sourceLine" id="cb48-5" data-line-number="5"><span class="co">#&gt; [6] &lt;NA&gt;     &lt;NA&gt;    </span></a>
<a class="sourceLine" id="cb48-6" data-line-number="6"><span class="co">#&gt; Levels: 性别：男 性别：女</span></a></code></pre></div>
<p>初学者需要额外注意，R 代码不支持中文，中文以及特殊字符只能出现在字符串中，两者的换用是代码出错的常见原因。</p>
</div>
<div id="逻辑值" class="section level4">
<h4><span class="header-section-number">2.1.1.4</span> 逻辑值</h4>
<p>逻辑值仅有 2 个：<code>TRUE</code> 和 <code>FALSE</code>，对应缩写为 <code>T</code> 和 <code>F</code>。一般并不会直接使用逻辑值存储信息，而是使用它管理程序的逻辑，这一点在本章【控制结构与循环】一节中介绍。</p>
<p>逻辑值的另外一个重要作用是对数据取子集，相比于整数索引，它更加的高效。</p>
<p>我们先看一下如何利用整数索引提取子集，如提取变量 <code>heights</code> 的第 2 个元素：</p>
<div class="sourceCode" id="cb49"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb49-1" data-line-number="1">heights[<span class="dv">2</span>]</a>
<a class="sourceLine" id="cb49-2" data-line-number="2"><span class="co">#&gt; [1] 1.72</span></a></code></pre></div>
<p>再提取第 2 到第 5 个元素，这会形成新的向量：</p>
<div class="sourceCode" id="cb50"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb50-1" data-line-number="1">heights[<span class="dv">2</span><span class="op">:</span><span class="dv">5</span>]</a>
<a class="sourceLine" id="cb50-2" data-line-number="2"><span class="co">#&gt; [1] 1.72 1.80 1.66 1.65</span></a></code></pre></div>
<p>这里 <code>2:5</code> 是一个便捷操作，它生成了整数向量 <code>c(2, 3, 4, 5)</code>：</p>
<div class="sourceCode" id="cb51"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb51-1" data-line-number="1"><span class="dv">2</span><span class="op">:</span><span class="dv">5</span></a>
<a class="sourceLine" id="cb51-2" data-line-number="2"><span class="co">#&gt; [1] 2 3 4 5</span></a></code></pre></div>
<p>如果使用负号，将会去掉对应的元素：</p>
<div class="sourceCode" id="cb52"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb52-1" data-line-number="1">heights</a>
<a class="sourceLine" id="cb52-2" data-line-number="2"><span class="co">#&gt; [1] 1.70 1.72 1.80 1.66 1.65 1.88</span></a>
<a class="sourceLine" id="cb52-3" data-line-number="3">heights[<span class="op">-</span><span class="dv">2</span>]</a>
<a class="sourceLine" id="cb52-4" data-line-number="4"><span class="co">#&gt; [1] 1.70 1.80 1.66 1.65 1.88</span></a></code></pre></div>
<p>在实际工作中，需要提取的数据子集通常不会这么有序，因此需要借助比较运算符和 <code>which()</code> 函数获取子集数据的索引。</p>
<p>例如，找出身高大于 1.7 的数据：</p>
<div class="sourceCode" id="cb53"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb53-1" data-line-number="1"><span class="co"># 先使用 which() 找出索引</span></a>
<a class="sourceLine" id="cb53-2" data-line-number="2"><span class="kw">which</span>(heights <span class="op">&gt;</span><span class="st"> </span><span class="fl">1.7</span>)</a>
<a class="sourceLine" id="cb53-3" data-line-number="3"><span class="co">#&gt; [1] 2 3 6</span></a>
<a class="sourceLine" id="cb53-4" data-line-number="4"></a>
<a class="sourceLine" id="cb53-5" data-line-number="5"><span class="co"># 然后组合取子集操作提取子集数据</span></a>
<a class="sourceLine" id="cb53-6" data-line-number="6">heights[<span class="kw">which</span>(heights <span class="op">&gt;</span><span class="st"> </span><span class="fl">1.7</span>)]</a>
<a class="sourceLine" id="cb53-7" data-line-number="7"><span class="co">#&gt; [1] 1.72 1.80 1.88</span></a></code></pre></div>
<p>实际上，我们完全没有必要引入 <code>which()</code> 函数用来返回数据的整数索引，<code>heights &gt; 1.7</code> 比较的结果是一个逻辑值向量，它本身就可以作为索引用于提取子集。</p>
<div class="sourceCode" id="cb54"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb54-1" data-line-number="1">heights <span class="op">&gt;</span><span class="st"> </span><span class="fl">1.7</span></a>
<a class="sourceLine" id="cb54-2" data-line-number="2"><span class="co">#&gt; [1] FALSE  TRUE  TRUE FALSE FALSE  TRUE</span></a>
<a class="sourceLine" id="cb54-3" data-line-number="3">heights[heights <span class="op">&gt;</span><span class="st"> </span><span class="fl">1.7</span>]</a>
<a class="sourceLine" id="cb54-4" data-line-number="4"><span class="co">#&gt; [1] 1.72 1.80 1.88</span></a></code></pre></div>
<p><code>TRUE</code> 对应的元素被保留，而 <code>FALSE</code> 对应的元素被去除。请读者记住，逻辑索引是首选的取子集方式，它更加高效。</p>
</div>
<div id="深入向量" class="section level4">
<h4><span class="header-section-number">2.1.1.5</span> 深入向量</h4>
<p>向量除了保存数据，还可以保存与之相关的属性。例如，为了更好展示 <code>heights</code> 信息，我们可以增加名字属性。</p>
<div class="sourceCode" id="cb55"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb55-1" data-line-number="1"><span class="kw">names</span>(heights) &lt;-<span class="st"> </span><span class="kw">paste</span>(<span class="st">&quot;Student:&quot;</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">6</span>)</a>
<a class="sourceLine" id="cb55-2" data-line-number="2">heights</a>
<a class="sourceLine" id="cb55-3" data-line-number="3"><span class="co">#&gt; Student: 1 Student: 2 Student: 3 Student: 4 Student: 5 </span></a>
<a class="sourceLine" id="cb55-4" data-line-number="4"><span class="co">#&gt;       1.70       1.72       1.80       1.66       1.65 </span></a>
<a class="sourceLine" id="cb55-5" data-line-number="5"><span class="co">#&gt; Student: 6 </span></a>
<a class="sourceLine" id="cb55-6" data-line-number="6"><span class="co">#&gt;       1.88</span></a></code></pre></div>
<p>上述代码中，<code>paste()</code> 将两个向量粘贴到一起，默认中间存在空格。</p>
<div class="sourceCode" id="cb56"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb56-1" data-line-number="1"><span class="kw">paste</span>(<span class="st">&quot;Student:&quot;</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">6</span>)</a>
<a class="sourceLine" id="cb56-2" data-line-number="2"><span class="co">#&gt; [1] &quot;Student: 1&quot; &quot;Student: 2&quot; &quot;Student: 3&quot; &quot;Student: 4&quot;</span></a>
<a class="sourceLine" id="cb56-3" data-line-number="3"><span class="co">#&gt; [5] &quot;Student: 5&quot; &quot;Student: 6&quot;</span></a>
<a class="sourceLine" id="cb56-4" data-line-number="4"><span class="co"># 修改分隔符</span></a>
<a class="sourceLine" id="cb56-5" data-line-number="5"><span class="kw">paste</span>(<span class="st">&quot;Student&quot;</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">6</span>, <span class="dt">sep =</span> <span class="st">&quot;-&quot;</span>)</a>
<a class="sourceLine" id="cb56-6" data-line-number="6"><span class="co">#&gt; [1] &quot;Student-1&quot; &quot;Student-2&quot; &quot;Student-3&quot; &quot;Student-4&quot;</span></a>
<a class="sourceLine" id="cb56-7" data-line-number="7"><span class="co">#&gt; [5] &quot;Student-5&quot; &quot;Student-6&quot;</span></a></code></pre></div>
<p><code>names()</code> 函数不仅可以设定名字属性，还可以查看：</p>
<div class="sourceCode" id="cb57"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb57-1" data-line-number="1"><span class="kw">names</span>(heights)</a>
<a class="sourceLine" id="cb57-2" data-line-number="2"><span class="co">#&gt; [1] &quot;Student: 1&quot; &quot;Student: 2&quot; &quot;Student: 3&quot; &quot;Student: 4&quot;</span></a>
<a class="sourceLine" id="cb57-3" data-line-number="3"><span class="co">#&gt; [5] &quot;Student: 5&quot; &quot;Student: 6&quot;</span></a></code></pre></div>
<p>R 中很多函数都与 <code>names()</code> 类似，不仅可以用于修改，同时还可以用于获取对应的信息。</p>
<p>另外，R 对象所具有的属性可以通过 <code>attributes()</code> 函数查看：</p>
<div class="sourceCode" id="cb58"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb58-1" data-line-number="1"><span class="kw">attributes</span>(heights)</a>
<a class="sourceLine" id="cb58-2" data-line-number="2"><span class="co">#&gt; $names</span></a>
<a class="sourceLine" id="cb58-3" data-line-number="3"><span class="co">#&gt; [1] &quot;Student: 1&quot; &quot;Student: 2&quot; &quot;Student: 3&quot; &quot;Student: 4&quot;</span></a>
<a class="sourceLine" id="cb58-4" data-line-number="4"><span class="co">#&gt; [5] &quot;Student: 5&quot; &quot;Student: 6&quot;</span></a></code></pre></div>
<p>R 默认的类系统非常自由，我们可以任意设定属性，如增加一个班级属性：</p>
<div class="sourceCode" id="cb59"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb59-1" data-line-number="1"><span class="kw">attr</span>(heights, <span class="st">&quot;class-name&quot;</span>) &lt;-<span class="st"> &quot;A&quot;</span></a>
<a class="sourceLine" id="cb59-2" data-line-number="2"><span class="kw">attr</span>(heights, <span class="st">&quot;class-name&quot;</span>)</a>
<a class="sourceLine" id="cb59-3" data-line-number="3"><span class="co">#&gt; [1] &quot;A&quot;</span></a>
<a class="sourceLine" id="cb59-4" data-line-number="4"></a>
<a class="sourceLine" id="cb59-5" data-line-number="5"><span class="kw">attributes</span>(heights)</a>
<a class="sourceLine" id="cb59-6" data-line-number="6"><span class="co">#&gt; $names</span></a>
<a class="sourceLine" id="cb59-7" data-line-number="7"><span class="co">#&gt; [1] &quot;Student: 1&quot; &quot;Student: 2&quot; &quot;Student: 3&quot; &quot;Student: 4&quot;</span></a>
<a class="sourceLine" id="cb59-8" data-line-number="8"><span class="co">#&gt; [5] &quot;Student: 5&quot; &quot;Student: 6&quot;</span></a>
<a class="sourceLine" id="cb59-9" data-line-number="9"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb59-10" data-line-number="10"><span class="co">#&gt; $`class-name`</span></a>
<a class="sourceLine" id="cb59-11" data-line-number="11"><span class="co">#&gt; [1] &quot;A&quot;</span></a></code></pre></div>
<p>在创建向量时，一些函数会相当有用，如 <code>rep()</code>，它可以用来重复数据。</p>
<div class="sourceCode" id="cb60"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb60-1" data-line-number="1"><span class="kw">rep</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">4</span>, <span class="dv">3</span>)</a>
<a class="sourceLine" id="cb60-2" data-line-number="2"><span class="co">#&gt;  [1] 1 2 3 4 1 2 3 4 1 2 3 4</span></a>
<a class="sourceLine" id="cb60-3" data-line-number="3"><span class="kw">rep</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">4</span>, <span class="dt">each =</span> <span class="dv">3</span>)</a>
<a class="sourceLine" id="cb60-4" data-line-number="4"><span class="co">#&gt;  [1] 1 1 1 2 2 2 3 3 3 4 4 4</span></a></code></pre></div>
<p>读者如果想要更新部分向量值，直接对提取的子集重新赋值即可。</p>
<div class="sourceCode" id="cb61"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb61-1" data-line-number="1">heights2</a>
<a class="sourceLine" id="cb61-2" data-line-number="2"><span class="co">#&gt; [1] 1.70 1.72 1.80 1.66 1.65 1.88</span></a>
<a class="sourceLine" id="cb61-3" data-line-number="3">heights2[heights2 <span class="op">&gt;</span><span class="st"> </span><span class="fl">1.8</span>] &lt;-<span class="st"> </span><span class="fl">1.8</span></a>
<a class="sourceLine" id="cb61-4" data-line-number="4">heights2</a>
<a class="sourceLine" id="cb61-5" data-line-number="5"><span class="co">#&gt; [1] 1.70 1.72 1.80 1.66 1.65 1.80</span></a></code></pre></div>
</div>
</div>
<div id="数组与矩阵" class="section level3">
<h3><span class="header-section-number">2.1.2</span> 数组与矩阵</h3>
<p>我们前面看的的向量都是一个维度的，如果我们增加维度信息，将形成数组。2 维的数组比较常用，被称为矩阵。</p>
<p>创建一个 2x2x3 的数组：</p>
<div class="sourceCode" id="cb62"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb62-1" data-line-number="1"><span class="kw">array</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">12</span>, <span class="dt">dim =</span> <span class="kw">c</span>(<span class="dv">2</span>, <span class="dv">2</span>, <span class="dv">3</span>))</a>
<a class="sourceLine" id="cb62-2" data-line-number="2"><span class="co">#&gt; , , 1</span></a>
<a class="sourceLine" id="cb62-3" data-line-number="3"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb62-4" data-line-number="4"><span class="co">#&gt;      [,1] [,2]</span></a>
<a class="sourceLine" id="cb62-5" data-line-number="5"><span class="co">#&gt; [1,]    1    3</span></a>
<a class="sourceLine" id="cb62-6" data-line-number="6"><span class="co">#&gt; [2,]    2    4</span></a>
<a class="sourceLine" id="cb62-7" data-line-number="7"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb62-8" data-line-number="8"><span class="co">#&gt; , , 2</span></a>
<a class="sourceLine" id="cb62-9" data-line-number="9"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb62-10" data-line-number="10"><span class="co">#&gt;      [,1] [,2]</span></a>
<a class="sourceLine" id="cb62-11" data-line-number="11"><span class="co">#&gt; [1,]    5    7</span></a>
<a class="sourceLine" id="cb62-12" data-line-number="12"><span class="co">#&gt; [2,]    6    8</span></a>
<a class="sourceLine" id="cb62-13" data-line-number="13"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb62-14" data-line-number="14"><span class="co">#&gt; , , 3</span></a>
<a class="sourceLine" id="cb62-15" data-line-number="15"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb62-16" data-line-number="16"><span class="co">#&gt;      [,1] [,2]</span></a>
<a class="sourceLine" id="cb62-17" data-line-number="17"><span class="co">#&gt; [1,]    9   11</span></a>
<a class="sourceLine" id="cb62-18" data-line-number="18"><span class="co">#&gt; [2,]   10   12</span></a></code></pre></div>
<p>创建一个 4x3 的矩阵：</p>
<div class="sourceCode" id="cb63"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb63-1" data-line-number="1"><span class="kw">matrix</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">12</span>, <span class="dt">nrow =</span> <span class="dv">4</span>, <span class="dt">ncol =</span> <span class="dv">3</span>, <span class="dt">byrow =</span> <span class="ot">TRUE</span>)</a>
<a class="sourceLine" id="cb63-2" data-line-number="2"><span class="co">#&gt;      [,1] [,2] [,3]</span></a>
<a class="sourceLine" id="cb63-3" data-line-number="3"><span class="co">#&gt; [1,]    1    2    3</span></a>
<a class="sourceLine" id="cb63-4" data-line-number="4"><span class="co">#&gt; [2,]    4    5    6</span></a>
<a class="sourceLine" id="cb63-5" data-line-number="5"><span class="co">#&gt; [3,]    7    8    9</span></a>
<a class="sourceLine" id="cb63-6" data-line-number="6"><span class="co">#&gt; [4,]   10   11   12</span></a></code></pre></div>
<p>矩阵包含 2 个常用的属性，行名 <code>rownames</code> 和列名 <code>colnames</code>：</p>
<div class="sourceCode" id="cb64"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb64-1" data-line-number="1">M &lt;-<span class="st"> </span><span class="kw">matrix</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">12</span>, <span class="dt">nrow =</span> <span class="dv">4</span>, <span class="dt">ncol =</span> <span class="dv">3</span>, <span class="dt">byrow =</span> <span class="ot">TRUE</span>)</a>
<a class="sourceLine" id="cb64-2" data-line-number="2"><span class="kw">rownames</span>(M)</a>
<a class="sourceLine" id="cb64-3" data-line-number="3"><span class="co">#&gt; NULL</span></a>
<a class="sourceLine" id="cb64-4" data-line-number="4"><span class="kw">colnames</span>(M)</a>
<a class="sourceLine" id="cb64-5" data-line-number="5"><span class="co">#&gt; NULL</span></a></code></pre></div>
<p>上述创建矩阵时我们没有设定，所以默认是 <code>NULL</code>（空值）。我们可以自行设定：</p>
<div class="sourceCode" id="cb65"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb65-1" data-line-number="1"><span class="kw">rownames</span>(M) &lt;-<span class="st"> </span><span class="kw">paste0</span>(<span class="st">&quot;a&quot;</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">4</span>)</a>
<a class="sourceLine" id="cb65-2" data-line-number="2"><span class="kw">colnames</span>(M) &lt;-<span class="st"> </span><span class="kw">paste0</span>(<span class="st">&quot;b&quot;</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">3</span>)</a>
<a class="sourceLine" id="cb65-3" data-line-number="3">M</a>
<a class="sourceLine" id="cb65-4" data-line-number="4"><span class="co">#&gt;    b1 b2 b3</span></a>
<a class="sourceLine" id="cb65-5" data-line-number="5"><span class="co">#&gt; a1  1  2  3</span></a>
<a class="sourceLine" id="cb65-6" data-line-number="6"><span class="co">#&gt; a2  4  5  6</span></a>
<a class="sourceLine" id="cb65-7" data-line-number="7"><span class="co">#&gt; a3  7  8  9</span></a>
<a class="sourceLine" id="cb65-8" data-line-number="8"><span class="co">#&gt; a4 10 11 12</span></a></code></pre></div>
<p>还可以获取矩阵的维度信息：</p>
<div class="sourceCode" id="cb66"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb66-1" data-line-number="1"><span class="kw">dim</span>(M)</a>
<a class="sourceLine" id="cb66-2" data-line-number="2"><span class="co">#&gt; [1] 4 3</span></a>
<a class="sourceLine" id="cb66-3" data-line-number="3"><span class="co"># 行数</span></a>
<a class="sourceLine" id="cb66-4" data-line-number="4"><span class="kw">nrow</span>(M)</a>
<a class="sourceLine" id="cb66-5" data-line-number="5"><span class="co">#&gt; [1] 4</span></a>
<a class="sourceLine" id="cb66-6" data-line-number="6"><span class="co"># 列数</span></a>
<a class="sourceLine" id="cb66-7" data-line-number="7"><span class="kw">ncol</span>(M)</a>
<a class="sourceLine" id="cb66-8" data-line-number="8"><span class="co">#&gt; [1] 3</span></a></code></pre></div>
<p>针对数值矩阵，一些运算非常有用：</p>
<div class="sourceCode" id="cb67"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb67-1" data-line-number="1"><span class="co"># 矩阵和</span></a>
<a class="sourceLine" id="cb67-2" data-line-number="2"><span class="kw">sum</span>(M)</a>
<a class="sourceLine" id="cb67-3" data-line-number="3"><span class="co">#&gt; [1] 78</span></a>
<a class="sourceLine" id="cb67-4" data-line-number="4"><span class="co"># 矩阵均值</span></a>
<a class="sourceLine" id="cb67-5" data-line-number="5"><span class="kw">mean</span>(M)</a>
<a class="sourceLine" id="cb67-6" data-line-number="6"><span class="co">#&gt; [1] 6.5</span></a>
<a class="sourceLine" id="cb67-7" data-line-number="7"><span class="co"># 行和</span></a>
<a class="sourceLine" id="cb67-8" data-line-number="8"><span class="kw">rowSums</span>(M)</a>
<a class="sourceLine" id="cb67-9" data-line-number="9"><span class="co">#&gt; a1 a2 a3 a4 </span></a>
<a class="sourceLine" id="cb67-10" data-line-number="10"><span class="co">#&gt;  6 15 24 33</span></a>
<a class="sourceLine" id="cb67-11" data-line-number="11"><span class="co"># 列和</span></a>
<a class="sourceLine" id="cb67-12" data-line-number="12"><span class="kw">colSums</span>(M)</a>
<a class="sourceLine" id="cb67-13" data-line-number="13"><span class="co">#&gt; b1 b2 b3 </span></a>
<a class="sourceLine" id="cb67-14" data-line-number="14"><span class="co">#&gt; 22 26 30</span></a>
<a class="sourceLine" id="cb67-15" data-line-number="15"><span class="co"># 行均值</span></a>
<a class="sourceLine" id="cb67-16" data-line-number="16"><span class="kw">rowMeans</span>(M)</a>
<a class="sourceLine" id="cb67-17" data-line-number="17"><span class="co">#&gt; a1 a2 a3 a4 </span></a>
<a class="sourceLine" id="cb67-18" data-line-number="18"><span class="co">#&gt;  2  5  8 11</span></a>
<a class="sourceLine" id="cb67-19" data-line-number="19"><span class="co"># 列均值</span></a>
<a class="sourceLine" id="cb67-20" data-line-number="20"><span class="kw">colMeans</span>(M)</a>
<a class="sourceLine" id="cb67-21" data-line-number="21"><span class="co">#&gt;  b1  b2  b3 </span></a>
<a class="sourceLine" id="cb67-22" data-line-number="22"><span class="co">#&gt; 5.5 6.5 7.5</span></a></code></pre></div>
<p>取子集操作依旧是适用的，逗号 <code>,</code> 用于分割不同的维度：</p>
<div class="sourceCode" id="cb68"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb68-1" data-line-number="1"><span class="co"># 第 1 行第 1 列的元素</span></a>
<a class="sourceLine" id="cb68-2" data-line-number="2">M[<span class="dv">1</span>, <span class="dv">1</span>]</a>
<a class="sourceLine" id="cb68-3" data-line-number="3"><span class="co">#&gt; [1] 1</span></a>
<a class="sourceLine" id="cb68-4" data-line-number="4"><span class="co"># 第 1 行</span></a>
<a class="sourceLine" id="cb68-5" data-line-number="5">M[<span class="dv">1</span>, ]</a>
<a class="sourceLine" id="cb68-6" data-line-number="6"><span class="co">#&gt; b1 b2 b3 </span></a>
<a class="sourceLine" id="cb68-7" data-line-number="7"><span class="co">#&gt;  1  2  3</span></a>
<a class="sourceLine" id="cb68-8" data-line-number="8"><span class="co"># 第 1 列</span></a>
<a class="sourceLine" id="cb68-9" data-line-number="9">M[, <span class="dv">1</span>]</a>
<a class="sourceLine" id="cb68-10" data-line-number="10"><span class="co">#&gt; a1 a2 a3 a4 </span></a>
<a class="sourceLine" id="cb68-11" data-line-number="11"><span class="co">#&gt;  1  4  7 10</span></a>
<a class="sourceLine" id="cb68-12" data-line-number="12"><span class="co"># 前 2 行</span></a>
<a class="sourceLine" id="cb68-13" data-line-number="13">M[<span class="dv">1</span><span class="op">:</span><span class="dv">2</span>, ]</a>
<a class="sourceLine" id="cb68-14" data-line-number="14"><span class="co">#&gt;    b1 b2 b3</span></a>
<a class="sourceLine" id="cb68-15" data-line-number="15"><span class="co">#&gt; a1  1  2  3</span></a>
<a class="sourceLine" id="cb68-16" data-line-number="16"><span class="co">#&gt; a2  4  5  6</span></a>
<a class="sourceLine" id="cb68-17" data-line-number="17"><span class="co"># 前 2 列</span></a>
<a class="sourceLine" id="cb68-18" data-line-number="18">M[, <span class="dv">1</span><span class="op">:</span><span class="dv">2</span>]</a>
<a class="sourceLine" id="cb68-19" data-line-number="19"><span class="co">#&gt;    b1 b2</span></a>
<a class="sourceLine" id="cb68-20" data-line-number="20"><span class="co">#&gt; a1  1  2</span></a>
<a class="sourceLine" id="cb68-21" data-line-number="21"><span class="co">#&gt; a2  4  5</span></a>
<a class="sourceLine" id="cb68-22" data-line-number="22"><span class="co">#&gt; a3  7  8</span></a>
<a class="sourceLine" id="cb68-23" data-line-number="23"><span class="co">#&gt; a4 10 11</span></a></code></pre></div>
<p>当取单行时，由于维度信息默认丢失，返回的是一维向量，我们可以显式指定保留矩阵形式，如：</p>
<div class="sourceCode" id="cb69"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb69-1" data-line-number="1">M[, <span class="dv">1</span>, drop =<span class="st"> </span><span class="ot">FALSE</span>]</a>
<a class="sourceLine" id="cb69-2" data-line-number="2"><span class="co">#&gt;    b1</span></a>
<a class="sourceLine" id="cb69-3" data-line-number="3"><span class="co">#&gt; a1  1</span></a>
<a class="sourceLine" id="cb69-4" data-line-number="4"><span class="co">#&gt; a2  4</span></a>
<a class="sourceLine" id="cb69-5" data-line-number="5"><span class="co">#&gt; a3  7</span></a>
<a class="sourceLine" id="cb69-6" data-line-number="6"><span class="co">#&gt; a4 10</span></a></code></pre></div>
<p>逻辑索引也可以使用：</p>
<div class="sourceCode" id="cb70"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb70-1" data-line-number="1">M[<span class="kw">rowMeans</span>(M) <span class="op">&gt;</span><span class="st"> </span><span class="dv">5</span>, ]</a>
<a class="sourceLine" id="cb70-2" data-line-number="2"><span class="co">#&gt;    b1 b2 b3</span></a>
<a class="sourceLine" id="cb70-3" data-line-number="3"><span class="co">#&gt; a3  7  8  9</span></a>
<a class="sourceLine" id="cb70-4" data-line-number="4"><span class="co">#&gt; a4 10 11 12</span></a></code></pre></div>
</div>
<div id="数据框" class="section level3">
<h3><span class="header-section-number">2.1.3</span> 数据框</h3>
<p>数据框（<code>data.frame</code>）是 R 中非常独特的一种数据结构，它可以非常好存储和展示常见的表格数据。从外形上看，它与矩阵非常相似，但与矩阵不同的是，数据框的列可以是不同的数据类型。</p>
<p>例如，创建一个数据框存储性别，年龄和身高数据。</p>
<div class="sourceCode" id="cb71"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb71-1" data-line-number="1">df &lt;-<span class="st"> </span><span class="kw">data.frame</span>(</a>
<a class="sourceLine" id="cb71-2" data-line-number="2">  <span class="dt">sex =</span> <span class="kw">c</span>(<span class="st">&quot;F&quot;</span>, <span class="st">&quot;M&quot;</span>, <span class="st">&quot;M&quot;</span>, <span class="st">&quot;F&quot;</span>),</a>
<a class="sourceLine" id="cb71-3" data-line-number="3">  <span class="dt">age =</span> <span class="kw">c</span>(<span class="dv">17</span>, <span class="dv">29</span>, <span class="dv">20</span>, <span class="dv">33</span>),</a>
<a class="sourceLine" id="cb71-4" data-line-number="4">  <span class="dt">heights =</span> <span class="kw">c</span>(<span class="fl">1.66</span>, <span class="fl">1.84</span>, <span class="fl">1.83</span>, <span class="fl">1.56</span>)</a>
<a class="sourceLine" id="cb71-5" data-line-number="5">)</a>
<a class="sourceLine" id="cb71-6" data-line-number="6"></a>
<a class="sourceLine" id="cb71-7" data-line-number="7">df</a>
<a class="sourceLine" id="cb71-8" data-line-number="8"><span class="co">#&gt;   sex age heights</span></a>
<a class="sourceLine" id="cb71-9" data-line-number="9"><span class="co">#&gt; 1   F  17    1.66</span></a>
<a class="sourceLine" id="cb71-10" data-line-number="10"><span class="co">#&gt; 2   M  29    1.84</span></a>
<a class="sourceLine" id="cb71-11" data-line-number="11"><span class="co">#&gt; 3   M  20    1.83</span></a>
<a class="sourceLine" id="cb71-12" data-line-number="12"><span class="co">#&gt; 4   F  33    1.56</span></a></code></pre></div>
<p><code>str()</code> 非常方便用于观察复杂数据类型的结构：</p>
<div class="sourceCode" id="cb72"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb72-1" data-line-number="1"><span class="kw">str</span>(df)</a>
<a class="sourceLine" id="cb72-2" data-line-number="2"><span class="co">#&gt; &#39;data.frame&#39;:    4 obs. of  3 variables:</span></a>
<a class="sourceLine" id="cb72-3" data-line-number="3"><span class="co">#&gt;  $ sex    : chr  &quot;F&quot; &quot;M&quot; &quot;M&quot; &quot;F&quot;</span></a>
<a class="sourceLine" id="cb72-4" data-line-number="4"><span class="co">#&gt;  $ age    : num  17 29 20 33</span></a>
<a class="sourceLine" id="cb72-5" data-line-number="5"><span class="co">#&gt;  $ heights: num  1.66 1.84 1.83 1.56</span></a></code></pre></div>
<p>默认，数据框中字符列会被自动转换为因子类型，我们可以通过设定修改它。</p>
<div class="sourceCode" id="cb73"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb73-1" data-line-number="1">df &lt;-<span class="st"> </span><span class="kw">data.frame</span>(</a>
<a class="sourceLine" id="cb73-2" data-line-number="2">  <span class="dt">sex =</span> <span class="kw">c</span>(<span class="st">&quot;F&quot;</span>, <span class="st">&quot;M&quot;</span>, <span class="st">&quot;M&quot;</span>, <span class="st">&quot;F&quot;</span>),</a>
<a class="sourceLine" id="cb73-3" data-line-number="3">  <span class="dt">age =</span> <span class="kw">c</span>(<span class="dv">17</span>, <span class="dv">29</span>, <span class="dv">20</span>, <span class="dv">33</span>),</a>
<a class="sourceLine" id="cb73-4" data-line-number="4">  <span class="dt">heights =</span> <span class="kw">c</span>(<span class="fl">1.66</span>, <span class="fl">1.84</span>, <span class="fl">1.83</span>, <span class="fl">1.56</span>),</a>
<a class="sourceLine" id="cb73-5" data-line-number="5">  <span class="dt">stringsAsFactors =</span> <span class="ot">FALSE</span></a>
<a class="sourceLine" id="cb73-6" data-line-number="6">)</a>
<a class="sourceLine" id="cb73-7" data-line-number="7"></a>
<a class="sourceLine" id="cb73-8" data-line-number="8">df</a>
<a class="sourceLine" id="cb73-9" data-line-number="9"><span class="co">#&gt;   sex age heights</span></a>
<a class="sourceLine" id="cb73-10" data-line-number="10"><span class="co">#&gt; 1   F  17    1.66</span></a>
<a class="sourceLine" id="cb73-11" data-line-number="11"><span class="co">#&gt; 2   M  29    1.84</span></a>
<a class="sourceLine" id="cb73-12" data-line-number="12"><span class="co">#&gt; 3   M  20    1.83</span></a>
<a class="sourceLine" id="cb73-13" data-line-number="13"><span class="co">#&gt; 4   F  33    1.56</span></a>
<a class="sourceLine" id="cb73-14" data-line-number="14"></a>
<a class="sourceLine" id="cb73-15" data-line-number="15"><span class="kw">str</span>(df)</a>
<a class="sourceLine" id="cb73-16" data-line-number="16"><span class="co">#&gt; &#39;data.frame&#39;:    4 obs. of  3 variables:</span></a>
<a class="sourceLine" id="cb73-17" data-line-number="17"><span class="co">#&gt;  $ sex    : chr  &quot;F&quot; &quot;M&quot; &quot;M&quot; &quot;F&quot;</span></a>
<a class="sourceLine" id="cb73-18" data-line-number="18"><span class="co">#&gt;  $ age    : num  17 29 20 33</span></a>
<a class="sourceLine" id="cb73-19" data-line-number="19"><span class="co">#&gt;  $ heights: num  1.66 1.84 1.83 1.56</span></a></code></pre></div>
<p>很多适用于矩阵的操作同样适用于数据框。</p>
<p>例如，获取维度信息：</p>
<div class="sourceCode" id="cb74"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb74-1" data-line-number="1"><span class="kw">dim</span>(df)</a>
<a class="sourceLine" id="cb74-2" data-line-number="2"><span class="co">#&gt; [1] 4 3</span></a>
<a class="sourceLine" id="cb74-3" data-line-number="3"><span class="co"># 行数</span></a>
<a class="sourceLine" id="cb74-4" data-line-number="4"><span class="kw">nrow</span>(df)</a>
<a class="sourceLine" id="cb74-5" data-line-number="5"><span class="co">#&gt; [1] 4</span></a>
<a class="sourceLine" id="cb74-6" data-line-number="6"><span class="co"># 列数</span></a>
<a class="sourceLine" id="cb74-7" data-line-number="7"><span class="kw">ncol</span>(df)</a>
<a class="sourceLine" id="cb74-8" data-line-number="8"><span class="co">#&gt; [1] 3</span></a></code></pre></div>
<p>例如，获取和设定行、列名：</p>
<div class="sourceCode" id="cb75"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb75-1" data-line-number="1"><span class="kw">rownames</span>(df)</a>
<a class="sourceLine" id="cb75-2" data-line-number="2"><span class="co">#&gt; [1] &quot;1&quot; &quot;2&quot; &quot;3&quot; &quot;4&quot;</span></a>
<a class="sourceLine" id="cb75-3" data-line-number="3"><span class="kw">colnames</span>(df)</a>
<a class="sourceLine" id="cb75-4" data-line-number="4"><span class="co">#&gt; [1] &quot;sex&quot;     &quot;age&quot;     &quot;heights&quot;</span></a>
<a class="sourceLine" id="cb75-5" data-line-number="5"></a>
<a class="sourceLine" id="cb75-6" data-line-number="6"><span class="kw">rownames</span>(df) &lt;-<span class="st"> </span><span class="kw">paste0</span>(<span class="st">&quot;Stu&quot;</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">4</span>)</a>
<a class="sourceLine" id="cb75-7" data-line-number="7"><span class="co"># 将列名大写</span></a>
<a class="sourceLine" id="cb75-8" data-line-number="8"><span class="kw">colnames</span>(df) &lt;-<span class="st"> </span><span class="kw">toupper</span>(<span class="kw">colnames</span>(df))</a>
<a class="sourceLine" id="cb75-9" data-line-number="9">df</a>
<a class="sourceLine" id="cb75-10" data-line-number="10"><span class="co">#&gt;      SEX AGE HEIGHTS</span></a>
<a class="sourceLine" id="cb75-11" data-line-number="11"><span class="co">#&gt; Stu1   F  17    1.66</span></a>
<a class="sourceLine" id="cb75-12" data-line-number="12"><span class="co">#&gt; Stu2   M  29    1.84</span></a>
<a class="sourceLine" id="cb75-13" data-line-number="13"><span class="co">#&gt; Stu3   M  20    1.83</span></a>
<a class="sourceLine" id="cb75-14" data-line-number="14"><span class="co">#&gt; Stu4   F  33    1.56</span></a></code></pre></div>
<p>数据框支持多种取子集的操作，包括整数索引、逻辑索引、行列名。</p>
<p>先看整数索引：</p>
<div class="sourceCode" id="cb76"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb76-1" data-line-number="1">df[<span class="dv">1</span><span class="op">:</span><span class="dv">2</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">2</span>]</a>
<a class="sourceLine" id="cb76-2" data-line-number="2"><span class="co">#&gt;      SEX AGE</span></a>
<a class="sourceLine" id="cb76-3" data-line-number="3"><span class="co">#&gt; Stu1   F  17</span></a>
<a class="sourceLine" id="cb76-4" data-line-number="4"><span class="co">#&gt; Stu2   M  29</span></a></code></pre></div>
<p>再看逻辑索引：</p>
<div class="sourceCode" id="cb77"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb77-1" data-line-number="1">df[<span class="kw">c</span>(<span class="ot">TRUE</span>, <span class="ot">TRUE</span>, <span class="ot">FALSE</span>, <span class="ot">FALSE</span>), <span class="kw">c</span>(<span class="ot">TRUE</span>, <span class="ot">TRUE</span>, <span class="ot">FALSE</span>)]</a>
<a class="sourceLine" id="cb77-2" data-line-number="2"><span class="co">#&gt;      SEX AGE</span></a>
<a class="sourceLine" id="cb77-3" data-line-number="3"><span class="co">#&gt; Stu1   F  17</span></a>
<a class="sourceLine" id="cb77-4" data-line-number="4"><span class="co">#&gt; Stu2   M  29</span></a>
<a class="sourceLine" id="cb77-5" data-line-number="5"><span class="co"># 等价于</span></a>
<a class="sourceLine" id="cb77-6" data-line-number="6">df[<span class="kw">rownames</span>(df) <span class="op">%in%</span><span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;Stu1&quot;</span>, <span class="st">&quot;Stu2&quot;</span>), <span class="kw">colnames</span>(df) <span class="op">%in%</span><span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;SEX&quot;</span>, <span class="st">&quot;AGE&quot;</span>)]</a>
<a class="sourceLine" id="cb77-7" data-line-number="7"><span class="co">#&gt;      SEX AGE</span></a>
<a class="sourceLine" id="cb77-8" data-line-number="8"><span class="co">#&gt; Stu1   F  17</span></a>
<a class="sourceLine" id="cb77-9" data-line-number="9"><span class="co">#&gt; Stu2   M  29</span></a></code></pre></div>
<p>这里 <code>%in%</code> 运算符是成员判断操作，如 <code>'a' %in% c('a', 'b')</code> 是判断 <code>'a'</code> 是否在字符串向量 <code>c('a', 'b')</code> 中。第二种写法看起来比较繁琐，但实际工作中比较常用。</p>
<p>我们还可以直接使用名字：</p>
<div class="sourceCode" id="cb78"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb78-1" data-line-number="1">df[<span class="kw">c</span>(<span class="st">&quot;Stu1&quot;</span>, <span class="st">&quot;Stu2&quot;</span>), <span class="kw">c</span>(<span class="st">&quot;SEX&quot;</span>, <span class="st">&quot;AGE&quot;</span>)]</a>
<a class="sourceLine" id="cb78-2" data-line-number="2"><span class="co">#&gt;      SEX AGE</span></a>
<a class="sourceLine" id="cb78-3" data-line-number="3"><span class="co">#&gt; Stu1   F  17</span></a>
<a class="sourceLine" id="cb78-4" data-line-number="4"><span class="co">#&gt; Stu2   M  29</span></a></code></pre></div>
<p>单独提取某一列生成一个向量是一个常用操作，读者可以使用两种操作符，包括 <code>[[]]</code> 和 <code>$</code>。</p>
<p>例如提取 <code>SEX</code> 列：</p>
<div class="sourceCode" id="cb79"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb79-1" data-line-number="1">df[[<span class="dv">1</span>]]</a>
<a class="sourceLine" id="cb79-2" data-line-number="2"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot; &quot;M&quot; &quot;F&quot;</span></a>
<a class="sourceLine" id="cb79-3" data-line-number="3">df[[<span class="st">&quot;SEX&quot;</span>]]</a>
<a class="sourceLine" id="cb79-4" data-line-number="4"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot; &quot;M&quot; &quot;F&quot;</span></a>
<a class="sourceLine" id="cb79-5" data-line-number="5">df<span class="op">$</span>SEX</a>
<a class="sourceLine" id="cb79-6" data-line-number="6"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot; &quot;M&quot; &quot;F&quot;</span></a></code></pre></div>
<p>需要注意 <code>[[]]</code> 与 <code>[]</code> 的区别，后者依旧返回一个数据框：</p>
<div class="sourceCode" id="cb80"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb80-1" data-line-number="1">df[<span class="st">&#39;SEX&#39;</span>]</a>
<a class="sourceLine" id="cb80-2" data-line-number="2"><span class="co">#&gt;      SEX</span></a>
<a class="sourceLine" id="cb80-3" data-line-number="3"><span class="co">#&gt; Stu1   F</span></a>
<a class="sourceLine" id="cb80-4" data-line-number="4"><span class="co">#&gt; Stu2   M</span></a>
<a class="sourceLine" id="cb80-5" data-line-number="5"><span class="co">#&gt; Stu3   M</span></a>
<a class="sourceLine" id="cb80-6" data-line-number="6"><span class="co">#&gt; Stu4   F</span></a></code></pre></div>
<p>另外，取子集操作可以使用 R 提供的 <code>subset()</code> 函数：</p>
<div class="sourceCode" id="cb81"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb81-1" data-line-number="1"><span class="co"># 取行</span></a>
<a class="sourceLine" id="cb81-2" data-line-number="2"><span class="kw">subset</span>(df, <span class="dt">subset =</span> <span class="kw">rownames</span>(df) <span class="op">%in%</span><span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;Stu1&quot;</span>, <span class="st">&quot;Stu2&quot;</span>))</a>
<a class="sourceLine" id="cb81-3" data-line-number="3"><span class="co">#&gt;      SEX AGE HEIGHTS</span></a>
<a class="sourceLine" id="cb81-4" data-line-number="4"><span class="co">#&gt; Stu1   F  17    1.66</span></a>
<a class="sourceLine" id="cb81-5" data-line-number="5"><span class="co">#&gt; Stu2   M  29    1.84</span></a>
<a class="sourceLine" id="cb81-6" data-line-number="6"><span class="co"># 取列</span></a>
<a class="sourceLine" id="cb81-7" data-line-number="7"><span class="kw">subset</span>(df, <span class="dt">select =</span> <span class="kw">colnames</span>(df) <span class="op">==</span><span class="st"> &quot;SEX&quot;</span>)</a>
<a class="sourceLine" id="cb81-8" data-line-number="8"><span class="co">#&gt;      SEX</span></a>
<a class="sourceLine" id="cb81-9" data-line-number="9"><span class="co">#&gt; Stu1   F</span></a>
<a class="sourceLine" id="cb81-10" data-line-number="10"><span class="co">#&gt; Stu2   M</span></a>
<a class="sourceLine" id="cb81-11" data-line-number="11"><span class="co">#&gt; Stu3   M</span></a>
<a class="sourceLine" id="cb81-12" data-line-number="12"><span class="co">#&gt; Stu4   F</span></a>
<a class="sourceLine" id="cb81-13" data-line-number="13"><span class="co"># 同时筛选行和列</span></a>
<a class="sourceLine" id="cb81-14" data-line-number="14"><span class="kw">subset</span>(df, <span class="dt">subset =</span> <span class="kw">rownames</span>(df) <span class="op">%in%</span><span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;Stu1&quot;</span>, <span class="st">&quot;Stu2&quot;</span>),</a>
<a class="sourceLine" id="cb81-15" data-line-number="15">           <span class="dt">select =</span> <span class="kw">colnames</span>(df) <span class="op">==</span><span class="st"> &quot;SEX&quot;</span>)</a>
<a class="sourceLine" id="cb81-16" data-line-number="16"><span class="co">#&gt;      SEX</span></a>
<a class="sourceLine" id="cb81-17" data-line-number="17"><span class="co">#&gt; Stu1   F</span></a>
<a class="sourceLine" id="cb81-18" data-line-number="18"><span class="co">#&gt; Stu2   M</span></a></code></pre></div>
<p>数据框如果想要修改或更新某列，像向量一样重新赋值即可：</p>
<div class="sourceCode" id="cb82"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb82-1" data-line-number="1">df<span class="op">$</span>AGE &lt;-<span class="st"> </span><span class="dv">20</span></a>
<a class="sourceLine" id="cb82-2" data-line-number="2">df</a>
<a class="sourceLine" id="cb82-3" data-line-number="3"><span class="co">#&gt;      SEX AGE HEIGHTS</span></a>
<a class="sourceLine" id="cb82-4" data-line-number="4"><span class="co">#&gt; Stu1   F  20    1.66</span></a>
<a class="sourceLine" id="cb82-5" data-line-number="5"><span class="co">#&gt; Stu2   M  20    1.84</span></a>
<a class="sourceLine" id="cb82-6" data-line-number="6"><span class="co">#&gt; Stu3   M  20    1.83</span></a>
<a class="sourceLine" id="cb82-7" data-line-number="7"><span class="co">#&gt; Stu4   F  20    1.56</span></a></code></pre></div>
</div>
<div id="列表" class="section level3">
<h3><span class="header-section-number">2.1.4</span> 列表</h3>
<p>列表可以表示<strong>非常非常非常复杂</strong>的数据结构。数据框可以看作列表所有列元素长度相同的特例。</p>
<p>创建一个列表如下：</p>
<div class="sourceCode" id="cb83"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb83-1" data-line-number="1">l &lt;-<span class="st"> </span><span class="kw">list</span>(</a>
<a class="sourceLine" id="cb83-2" data-line-number="2">  <span class="dt">sex =</span> <span class="kw">c</span>(<span class="st">&quot;F&quot;</span>, <span class="st">&quot;M&quot;</span>),</a>
<a class="sourceLine" id="cb83-3" data-line-number="3">  <span class="dt">age =</span> <span class="kw">c</span>(<span class="dv">17</span>, <span class="dv">29</span>, <span class="dv">20</span>),</a>
<a class="sourceLine" id="cb83-4" data-line-number="4">  <span class="dt">heights =</span> <span class="kw">c</span>(<span class="fl">1.66</span>, <span class="fl">1.84</span>, <span class="fl">1.83</span>, <span class="fl">1.56</span>)</a>
<a class="sourceLine" id="cb83-5" data-line-number="5">)</a>
<a class="sourceLine" id="cb83-6" data-line-number="6">l</a>
<a class="sourceLine" id="cb83-7" data-line-number="7"><span class="co">#&gt; $sex</span></a>
<a class="sourceLine" id="cb83-8" data-line-number="8"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot;</span></a>
<a class="sourceLine" id="cb83-9" data-line-number="9"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb83-10" data-line-number="10"><span class="co">#&gt; $age</span></a>
<a class="sourceLine" id="cb83-11" data-line-number="11"><span class="co">#&gt; [1] 17 29 20</span></a>
<a class="sourceLine" id="cb83-12" data-line-number="12"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb83-13" data-line-number="13"><span class="co">#&gt; $heights</span></a>
<a class="sourceLine" id="cb83-14" data-line-number="14"><span class="co">#&gt; [1] 1.66 1.84 1.83 1.56</span></a></code></pre></div>
<p>从输出上我们就可以知道如何提取不同的信息：</p>
<div class="sourceCode" id="cb84"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb84-1" data-line-number="1">l<span class="op">$</span>sex</a>
<a class="sourceLine" id="cb84-2" data-line-number="2"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot;</span></a>
<a class="sourceLine" id="cb84-3" data-line-number="3">l<span class="op">$</span>heights</a>
<a class="sourceLine" id="cb84-4" data-line-number="4"><span class="co">#&gt; [1] 1.66 1.84 1.83 1.56</span></a></code></pre></div>
<p>列表只有 <code>names</code> 属性，没有行列名属性：</p>
<div class="sourceCode" id="cb85"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb85-1" data-line-number="1"><span class="kw">names</span>(l)</a>
<a class="sourceLine" id="cb85-2" data-line-number="2"><span class="co">#&gt; [1] &quot;sex&quot;     &quot;age&quot;     &quot;heights&quot;</span></a></code></pre></div>
<p>类似于数据框，<code>[[]]</code> 取子集得到一个列表元素，而 <code>[]</code> 得到一个子列表。</p>
<div class="sourceCode" id="cb86"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb86-1" data-line-number="1">l[<span class="st">&#39;sex&#39;</span>]</a>
<a class="sourceLine" id="cb86-2" data-line-number="2"><span class="co">#&gt; $sex</span></a>
<a class="sourceLine" id="cb86-3" data-line-number="3"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot;</span></a>
<a class="sourceLine" id="cb86-4" data-line-number="4">l[[<span class="st">&#39;sex&#39;</span>]]</a>
<a class="sourceLine" id="cb86-5" data-line-number="5"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot;</span></a></code></pre></div>
<p>列表是支持嵌套的，下面我们将两个列表 <code>l</code> 放到一起：</p>
<div class="sourceCode" id="cb87"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb87-1" data-line-number="1">l2 &lt;-<span class="st"> </span>l</a>
<a class="sourceLine" id="cb87-2" data-line-number="2">l2<span class="op">$</span>l1 &lt;-<span class="st"> </span>l</a>
<a class="sourceLine" id="cb87-3" data-line-number="3">l2</a>
<a class="sourceLine" id="cb87-4" data-line-number="4"><span class="co">#&gt; $sex</span></a>
<a class="sourceLine" id="cb87-5" data-line-number="5"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot;</span></a>
<a class="sourceLine" id="cb87-6" data-line-number="6"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb87-7" data-line-number="7"><span class="co">#&gt; $age</span></a>
<a class="sourceLine" id="cb87-8" data-line-number="8"><span class="co">#&gt; [1] 17 29 20</span></a>
<a class="sourceLine" id="cb87-9" data-line-number="9"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb87-10" data-line-number="10"><span class="co">#&gt; $heights</span></a>
<a class="sourceLine" id="cb87-11" data-line-number="11"><span class="co">#&gt; [1] 1.66 1.84 1.83 1.56</span></a>
<a class="sourceLine" id="cb87-12" data-line-number="12"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb87-13" data-line-number="13"><span class="co">#&gt; $l1</span></a>
<a class="sourceLine" id="cb87-14" data-line-number="14"><span class="co">#&gt; $l1$sex</span></a>
<a class="sourceLine" id="cb87-15" data-line-number="15"><span class="co">#&gt; [1] &quot;F&quot; &quot;M&quot;</span></a>
<a class="sourceLine" id="cb87-16" data-line-number="16"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb87-17" data-line-number="17"><span class="co">#&gt; $l1$age</span></a>
<a class="sourceLine" id="cb87-18" data-line-number="18"><span class="co">#&gt; [1] 17 29 20</span></a>
<a class="sourceLine" id="cb87-19" data-line-number="19"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb87-20" data-line-number="20"><span class="co">#&gt; $l1$heights</span></a>
<a class="sourceLine" id="cb87-21" data-line-number="21"><span class="co">#&gt; [1] 1.66 1.84 1.83 1.56</span></a></code></pre></div>
</div>
</div>
<div id="控制结构" class="section level2">
<h2><span class="header-section-number">2.2</span> 控制结构</h2>
<p>在处理数据分析任务时，我们很少能够简单依赖命令的顺序执行就完成任务。为了处理程序的复杂逻辑以及减少代码量，我们需要学习条件与循环控制的使用。</p>
<div id="条件控制" class="section level3">
<h3><span class="header-section-number">2.2.1</span> 条件控制</h3>
<div id="if-语句" class="section level4">
<h4><span class="header-section-number">2.2.1.1</span> if 语句</h4>
<p>if 语句是最常用的条件结构，它由 if 关键字、条件判断语句和代码块组成：</p>
<div class="sourceCode" id="cb88"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb88-1" data-line-number="1">age &lt;-<span class="st">  </span><span class="dv">20</span></a>
<a class="sourceLine" id="cb88-2" data-line-number="2"><span class="cf">if</span> (age <span class="op">&gt;</span><span class="st"> </span><span class="dv">18</span>) {</a>
<a class="sourceLine" id="cb88-3" data-line-number="3">  <span class="co"># 如果条件判断结果为 TRUE</span></a>
<a class="sourceLine" id="cb88-4" data-line-number="4">  <span class="co"># 该代码块中的语句会执行</span></a>
<a class="sourceLine" id="cb88-5" data-line-number="5">  <span class="kw">message</span>(<span class="st">&quot;你是个成年人啦！&quot;</span>)</a>
<a class="sourceLine" id="cb88-6" data-line-number="6">}</a>
<a class="sourceLine" id="cb88-7" data-line-number="7"><span class="co">#&gt; 你是个成年人啦！</span></a></code></pre></div>
<p>条件判断语句结果必须返回一个逻辑值，即 <code>TRUE</code> 或 <code>FALSE</code>。如果返回为 <code>TRUE</code>，随后以 <code>{}</code> 包裹的代码块会被执行。如果我们要处理为 <code>FALSE</code> 的情况，增加一个可选的 else 语句块。</p>
<div class="sourceCode" id="cb89"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb89-1" data-line-number="1">age &lt;-<span class="st"> </span><span class="dv">16</span></a>
<a class="sourceLine" id="cb89-2" data-line-number="2"><span class="cf">if</span> (age <span class="op">&gt;</span><span class="st"> </span><span class="dv">18</span>) {</a>
<a class="sourceLine" id="cb89-3" data-line-number="3">  <span class="co"># 为 TRUE 时执行</span></a>
<a class="sourceLine" id="cb89-4" data-line-number="4">  <span class="kw">message</span>(<span class="st">&quot;你是个成年人啦！&quot;</span>)</a>
<a class="sourceLine" id="cb89-5" data-line-number="5">} <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb89-6" data-line-number="6">  <span class="co"># 为 FALSE 时执行</span></a>
<a class="sourceLine" id="cb89-7" data-line-number="7">  <span class="kw">message</span>(<span class="st">&quot;你还是个小孩子哟！&quot;</span>)</a>
<a class="sourceLine" id="cb89-8" data-line-number="8">}</a>
<a class="sourceLine" id="cb89-9" data-line-number="9"><span class="co">#&gt; 你还是个小孩子哟！</span></a></code></pre></div>
<p>代码块中可以包含任意代码，所以 if-else 语句是支持内部嵌套的，结构如下：</p>
<div class="sourceCode" id="cb90"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb90-1" data-line-number="1"><span class="cf">if</span> () {</a>
<a class="sourceLine" id="cb90-2" data-line-number="2">  <span class="cf">if</span> () {</a>
<a class="sourceLine" id="cb90-3" data-line-number="3">    </a>
<a class="sourceLine" id="cb90-4" data-line-number="4">  } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb90-5" data-line-number="5">    </a>
<a class="sourceLine" id="cb90-6" data-line-number="6">  }</a>
<a class="sourceLine" id="cb90-7" data-line-number="7">} <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb90-8" data-line-number="8">  </a>
<a class="sourceLine" id="cb90-9" data-line-number="9">}</a></code></pre></div>
<p>如果需要处理的情况是多种，if-else 语句可以连用。例如：</p>
<div class="sourceCode" id="cb91"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb91-1" data-line-number="1">age &lt;-<span class="st"> </span><span class="dv">17</span></a>
<a class="sourceLine" id="cb91-2" data-line-number="2"><span class="cf">if</span> (age <span class="op">&gt;</span><span class="st"> </span><span class="dv">18</span>) {</a>
<a class="sourceLine" id="cb91-3" data-line-number="3">  <span class="kw">message</span>(<span class="st">&quot;你是个成年人啦！&quot;</span>)</a>
<a class="sourceLine" id="cb91-4" data-line-number="4">} <span class="cf">else</span> <span class="cf">if</span> (age <span class="op">&lt;</span><span class="st"> </span><span class="dv">17</span>) {</a>
<a class="sourceLine" id="cb91-5" data-line-number="5">  <span class="kw">message</span>(<span class="st">&quot;你还是个小孩子哟！&quot;</span>)</a>
<a class="sourceLine" id="cb91-6" data-line-number="6">} <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb91-7" data-line-number="7">  <span class="kw">message</span>(<span class="st">&quot;恭喜你，快要成年了！&quot;</span>)</a>
<a class="sourceLine" id="cb91-8" data-line-number="8">}</a>
<a class="sourceLine" id="cb91-9" data-line-number="9"><span class="co">#&gt; 恭喜你，快要成年了！</span></a></code></pre></div>
</div>
<div id="switch-语句" class="section level4">
<h4><span class="header-section-number">2.2.1.2</span> switch 语句</h4>
<p>swtich 语句在 R 中存在，但读者会极少见到和使用它。结构如下：</p>
<div class="sourceCode" id="cb92"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb92-1" data-line-number="1"><span class="cf">switch</span>(EXPR, ...)</a></code></pre></div>
<p>这里 <code>EXPR</code> 指代表达式，而 <code>...</code> 说明可以输入任意参数。</p>
<p>这里只举一个简单的例子：</p>
<div class="sourceCode" id="cb93"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb93-1" data-line-number="1">ch &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="st">&quot;b&quot;</span>)</a>
<a class="sourceLine" id="cb93-2" data-line-number="2"><span class="kw">cat</span>(ch,<span class="st">&quot;:&quot;</span>, <span class="cf">switch</span>(<span class="dt">EXPR =</span> ch, <span class="dt">a =</span> <span class="dv">1</span>, <span class="dt">b =</span> <span class="dv">2</span><span class="op">:</span><span class="dv">3</span>), <span class="st">&quot;</span><span class="ch">\n</span><span class="st">&quot;</span>)</a>
<a class="sourceLine" id="cb93-3" data-line-number="3"><span class="co">#&gt; b : 2 3</span></a></code></pre></div>
<p>switch 与函数式编程结合更具不凡的威力，其他场景下我极少见到该语句被使用。因此，我建议初学者了解即可，不必掌握。当然，读者如果遇到非常适合的场景也不妨试一试它，应该是可以让代码更为精炼有效的。</p>
</div>
<div id="提示信息" class="section level4">
<h4><span class="header-section-number">2.2.1.3</span> 提示信息</h4>
<p>编写程序时，通过输出一些提示信息可以更好地显示程序的运行状态是否如我们所预期，这是一个初学者需要掌握的一个技巧，能有效避免错误和帮助调试错误。</p>
<p>R 可以通过 <code>print()</code>、<code>message()</code>、<code>cat()</code>、<code>warning()</code> 和 <code>stop()</code> 输出提示信息，只有 <code>stop()</code> 会让程序终止。</p>
<p>读者通过下面的输出比较前几者的差别：</p>
<div class="sourceCode" id="cb94"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb94-1" data-line-number="1"><span class="kw">print</span>(<span class="st">&quot;Running...&quot;</span>)</a>
<a class="sourceLine" id="cb94-2" data-line-number="2"><span class="co">#&gt; [1] &quot;Running...&quot;</span></a>
<a class="sourceLine" id="cb94-3" data-line-number="3"><span class="kw">message</span>(<span class="st">&quot;Running...&quot;</span>)</a>
<a class="sourceLine" id="cb94-4" data-line-number="4"><span class="co">#&gt; Running...</span></a>
<a class="sourceLine" id="cb94-5" data-line-number="5"><span class="kw">cat</span>(<span class="st">&quot;Running...</span><span class="ch">\n</span><span class="st">&quot;</span>)</a>
<a class="sourceLine" id="cb94-6" data-line-number="6"><span class="co">#&gt; Running...</span></a>
<a class="sourceLine" id="cb94-7" data-line-number="7"><span class="kw">warning</span>(<span class="st">&quot;Running...&quot;</span>)</a>
<a class="sourceLine" id="cb94-8" data-line-number="8"><span class="co">#&gt; Warning: Running...</span></a></code></pre></div>
<p><code>cat()</code> 与 <code>message()</code> 看起来差别不大，但 <code>cat()</code> 无法被禁止输出，默认没有换行。另外 <code>message()</code> 和 <code>warning()</code> 的信息是可以被抑制掉的，如下：</p>
<div class="sourceCode" id="cb95"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb95-1" data-line-number="1"><span class="kw">message</span>(<span class="st">&quot;Running...&quot;</span>)</a>
<a class="sourceLine" id="cb95-2" data-line-number="2"><span class="co">#&gt; Running...</span></a>
<a class="sourceLine" id="cb95-3" data-line-number="3"><span class="kw">suppressMessages</span>(<span class="kw">message</span>(<span class="st">&quot;Running...&quot;</span>))</a>
<a class="sourceLine" id="cb95-4" data-line-number="4"></a>
<a class="sourceLine" id="cb95-5" data-line-number="5"><span class="kw">warning</span>(<span class="st">&quot;Running...&quot;</span>)</a>
<a class="sourceLine" id="cb95-6" data-line-number="6"><span class="co">#&gt; Warning: Running...</span></a>
<a class="sourceLine" id="cb95-7" data-line-number="7"><span class="kw">suppressWarnings</span>(<span class="kw">warning</span>(<span class="st">&quot;Running...&quot;</span>))</a></code></pre></div>
<p>我们再来了解下 <code>stop()</code>，它会直接让程序终止掉，这可以有效避免正确的代码跑错误的数据。</p>
<p>例如，计算均值需要一个数值型数据，但我们却传递了一个字符串：</p>
<div class="sourceCode" id="cb96"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb96-1" data-line-number="1">heights_str &lt;-<span class="st"> </span><span class="kw">as.character</span>(heights)</a>
<a class="sourceLine" id="cb96-2" data-line-number="2"></a>
<a class="sourceLine" id="cb96-3" data-line-number="3"><span class="cf">if</span> (<span class="op">!</span><span class="kw">is.numeric</span>(heights_str)) {</a>
<a class="sourceLine" id="cb96-4" data-line-number="4">  <span class="kw">stop</span>(<span class="st">&quot;无法对字符串计算！&quot;</span>)</a>
<a class="sourceLine" id="cb96-5" data-line-number="5">} <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb96-6" data-line-number="6">  <span class="co"># 下面的代码不会被运行</span></a>
<a class="sourceLine" id="cb96-7" data-line-number="7">  mu &lt;-<span class="st"> </span><span class="kw">mean</span>(heights_str)</a>
<a class="sourceLine" id="cb96-8" data-line-number="8">}</a>
<a class="sourceLine" id="cb96-9" data-line-number="9"><span class="co">#&gt; Error in eval(expr, envir, enclos): 无法对字符串计算！</span></a></code></pre></div>
<p>一般情况下，我推荐读者按需使用 <code>message()</code>/<code>print()</code>、<code>warning()</code> 和 <code>stop()</code> 这几个函数，它们体现信息的 3 个不同级别：</p>
<ul>
<li><code>message()</code>/<code>print()</code> 提供普通的输出信息。</li>
<li><code>warning()</code> 提供需要注意的警告信息。</li>
<li><code>stop()</code> 提供令程序停止运行的信息。</li>
</ul>
</div>
</div>
<div id="循环控制" class="section level3">
<h3><span class="header-section-number">2.2.2</span> 循环控制</h3>
<p>当我们需要重复某一个（堆）操作时，就需要用到循环的力量了。R 中的循环语句效率历来被人诟病，但实际上已经大有改进。循环语句相比后面提到的 <code>apply</code> 家族函数具有更高的可读性，且容易理解和调试，因此我个人推荐初学者使用。如果本小节提到的几个循环控制语句确实影响到读者程序的效率，再找其他办法也不迟。</p>
<blockquote>
<p>在此强调一下，无论是程序的编写还是科研分析工作，<strong>完成</strong>永远比<strong>高效</strong>重要。</p>
</blockquote>
<div id="for-语句" class="section level4">
<h4><span class="header-section-number">2.2.2.1</span> for 语句</h4>
<p>for 语句需要配合迭代变量、in 关键字一起使用，结构如下：</p>
<div class="sourceCode" id="cb97"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb97-1" data-line-number="1"><span class="cf">for</span> (i <span class="cf">in</span> obj) {</a>
<a class="sourceLine" id="cb97-2" data-line-number="2">  <span class="co"># 这里输入任意条语句</span></a>
<a class="sourceLine" id="cb97-3" data-line-number="3">}</a></code></pre></div>
<p>这里 <code>i</code> 指代迭代变量，它可以是索引，也可以是子数据集。<code>obj</code> 指代一个可迭代对象。</p>
<p>针对循环打印变量 <code>heights</code> 的信息，可以有以下 2 种方式：</p>
<div class="sourceCode" id="cb98"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb98-1" data-line-number="1"><span class="co"># 第一种方式</span></a>
<a class="sourceLine" id="cb98-2" data-line-number="2"><span class="co"># 直接循环迭代对象本身</span></a>
<a class="sourceLine" id="cb98-3" data-line-number="3"><span class="cf">for</span> (i <span class="cf">in</span> heights) {</a>
<a class="sourceLine" id="cb98-4" data-line-number="4">  <span class="kw">print</span>(i)</a>
<a class="sourceLine" id="cb98-5" data-line-number="5">}</a>
<a class="sourceLine" id="cb98-6" data-line-number="6"><span class="co">#&gt; [1] 1.7</span></a>
<a class="sourceLine" id="cb98-7" data-line-number="7"><span class="co">#&gt; [1] 1.72</span></a>
<a class="sourceLine" id="cb98-8" data-line-number="8"><span class="co">#&gt; [1] 1.8</span></a>
<a class="sourceLine" id="cb98-9" data-line-number="9"><span class="co">#&gt; [1] 1.66</span></a>
<a class="sourceLine" id="cb98-10" data-line-number="10"><span class="co">#&gt; [1] 1.65</span></a>
<a class="sourceLine" id="cb98-11" data-line-number="11"><span class="co">#&gt; [1] 1.88</span></a>
<a class="sourceLine" id="cb98-12" data-line-number="12"></a>
<a class="sourceLine" id="cb98-13" data-line-number="13"><span class="co"># 第二种方式</span></a>
<a class="sourceLine" id="cb98-14" data-line-number="14"><span class="co"># 通过索引进行迭代</span></a>
<a class="sourceLine" id="cb98-15" data-line-number="15"><span class="cf">for</span> (i <span class="cf">in</span> <span class="dv">1</span><span class="op">:</span><span class="kw">length</span>(heights)) {</a>
<a class="sourceLine" id="cb98-16" data-line-number="16">  <span class="kw">print</span>(heights[i])</a>
<a class="sourceLine" id="cb98-17" data-line-number="17">}</a>
<a class="sourceLine" id="cb98-18" data-line-number="18"><span class="co">#&gt; Student: 1 </span></a>
<a class="sourceLine" id="cb98-19" data-line-number="19"><span class="co">#&gt;        1.7 </span></a>
<a class="sourceLine" id="cb98-20" data-line-number="20"><span class="co">#&gt; Student: 2 </span></a>
<a class="sourceLine" id="cb98-21" data-line-number="21"><span class="co">#&gt;       1.72 </span></a>
<a class="sourceLine" id="cb98-22" data-line-number="22"><span class="co">#&gt; Student: 3 </span></a>
<a class="sourceLine" id="cb98-23" data-line-number="23"><span class="co">#&gt;        1.8 </span></a>
<a class="sourceLine" id="cb98-24" data-line-number="24"><span class="co">#&gt; Student: 4 </span></a>
<a class="sourceLine" id="cb98-25" data-line-number="25"><span class="co">#&gt;       1.66 </span></a>
<a class="sourceLine" id="cb98-26" data-line-number="26"><span class="co">#&gt; Student: 5 </span></a>
<a class="sourceLine" id="cb98-27" data-line-number="27"><span class="co">#&gt;       1.65 </span></a>
<a class="sourceLine" id="cb98-28" data-line-number="28"><span class="co">#&gt; Student: 6 </span></a>
<a class="sourceLine" id="cb98-29" data-line-number="29"><span class="co">#&gt;       1.88</span></a></code></pre></div>
<p>第二种方式写法看起来更为复杂，但如果针对一些复杂的程序，它则显得更加逻辑分明。</p>
<p>初学者容易犯的一个错误是将 in 后面的可迭代对象写成一个标量，如下：</p>
<div class="sourceCode" id="cb99"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb99-1" data-line-number="1"><span class="cf">for</span> (i <span class="cf">in</span> <span class="kw">length</span>(heights)) {</a>
<a class="sourceLine" id="cb99-2" data-line-number="2">  <span class="kw">print</span>(heights[i])</a>
<a class="sourceLine" id="cb99-3" data-line-number="3">}</a>
<a class="sourceLine" id="cb99-4" data-line-number="4"><span class="co">#&gt; Student: 6 </span></a>
<a class="sourceLine" id="cb99-5" data-line-number="5"><span class="co">#&gt;       1.88</span></a></code></pre></div>
<p>需要注意下面两者的区别：</p>
<div class="sourceCode" id="cb100"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb100-1" data-line-number="1"><span class="kw">length</span>(heights)</a>
<a class="sourceLine" id="cb100-2" data-line-number="2"><span class="co">#&gt; [1] 6</span></a>
<a class="sourceLine" id="cb100-3" data-line-number="3"></a>
<a class="sourceLine" id="cb100-4" data-line-number="4"><span class="dv">1</span><span class="op">:</span><span class="kw">length</span>(heights)</a>
<a class="sourceLine" id="cb100-5" data-line-number="5"><span class="co">#&gt; [1] 1 2 3 4 5 6</span></a></code></pre></div>
<p>一种更好的写法是使用 <code>seq_along(heights)</code> 替代 <code>1:length(heights)</code>：</p>
<div class="sourceCode" id="cb101"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb101-1" data-line-number="1"><span class="cf">for</span> (i <span class="cf">in</span> <span class="kw">seq_along</span>(heights)) {</a>
<a class="sourceLine" id="cb101-2" data-line-number="2">  <span class="kw">print</span>(heights[i])</a>
<a class="sourceLine" id="cb101-3" data-line-number="3">}</a>
<a class="sourceLine" id="cb101-4" data-line-number="4"><span class="co">#&gt; Student: 1 </span></a>
<a class="sourceLine" id="cb101-5" data-line-number="5"><span class="co">#&gt;        1.7 </span></a>
<a class="sourceLine" id="cb101-6" data-line-number="6"><span class="co">#&gt; Student: 2 </span></a>
<a class="sourceLine" id="cb101-7" data-line-number="7"><span class="co">#&gt;       1.72 </span></a>
<a class="sourceLine" id="cb101-8" data-line-number="8"><span class="co">#&gt; Student: 3 </span></a>
<a class="sourceLine" id="cb101-9" data-line-number="9"><span class="co">#&gt;        1.8 </span></a>
<a class="sourceLine" id="cb101-10" data-line-number="10"><span class="co">#&gt; Student: 4 </span></a>
<a class="sourceLine" id="cb101-11" data-line-number="11"><span class="co">#&gt;       1.66 </span></a>
<a class="sourceLine" id="cb101-12" data-line-number="12"><span class="co">#&gt; Student: 5 </span></a>
<a class="sourceLine" id="cb101-13" data-line-number="13"><span class="co">#&gt;       1.65 </span></a>
<a class="sourceLine" id="cb101-14" data-line-number="14"><span class="co">#&gt; Student: 6 </span></a>
<a class="sourceLine" id="cb101-15" data-line-number="15"><span class="co">#&gt;       1.88</span></a></code></pre></div>
<p><code>seq_along()</code> 会自动返回可迭代对象的索引序列：</p>
<div class="sourceCode" id="cb102"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb102-1" data-line-number="1"><span class="kw">seq_along</span>(heights)</a>
<a class="sourceLine" id="cb102-2" data-line-number="2"><span class="co">#&gt; [1] 1 2 3 4 5 6</span></a></code></pre></div>
</div>
<div id="while-语句" class="section level4">
<h4><span class="header-section-number">2.2.2.2</span> while 语句</h4>
<p>for 语句已经能满足一般场景的使用，while 语句则特别适合于算法的设计中：</p>
<ul>
<li>不知道要运行多少次循环。</li>
<li>知道要退出循环的条件。</li>
</ul>
<p>下面举一个简单的例子：</p>
<div class="sourceCode" id="cb103"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb103-1" data-line-number="1">v &lt;-<span class="st"> </span><span class="dv">10</span></a>
<a class="sourceLine" id="cb103-2" data-line-number="2"><span class="cf">while</span>(v <span class="op">&gt;</span><span class="st"> </span><span class="dv">2</span>) {</a>
<a class="sourceLine" id="cb103-3" data-line-number="3">  <span class="kw">print</span>(v)</a>
<a class="sourceLine" id="cb103-4" data-line-number="4">  v &lt;-<span class="st"> </span>v <span class="op">-</span><span class="st"> </span><span class="fl">1.1</span></a>
<a class="sourceLine" id="cb103-5" data-line-number="5">}</a>
<a class="sourceLine" id="cb103-6" data-line-number="6"><span class="co">#&gt; [1] 10</span></a>
<a class="sourceLine" id="cb103-7" data-line-number="7"><span class="co">#&gt; [1] 8.9</span></a>
<a class="sourceLine" id="cb103-8" data-line-number="8"><span class="co">#&gt; [1] 7.8</span></a>
<a class="sourceLine" id="cb103-9" data-line-number="9"><span class="co">#&gt; [1] 6.7</span></a>
<a class="sourceLine" id="cb103-10" data-line-number="10"><span class="co">#&gt; [1] 5.6</span></a>
<a class="sourceLine" id="cb103-11" data-line-number="11"><span class="co">#&gt; [1] 4.5</span></a>
<a class="sourceLine" id="cb103-12" data-line-number="12"><span class="co">#&gt; [1] 3.4</span></a>
<a class="sourceLine" id="cb103-13" data-line-number="13"><span class="co">#&gt; [1] 2.3</span></a></code></pre></div>
</div>
<div id="repeat-语句与循环退出" class="section level4">
<h4><span class="header-section-number">2.2.2.3</span> repeat 语句与循环退出</h4>
<p>repeat 语句我从来没有使用过，它类似与 C 语言中的 do-while 语句，即先运行一段程序，然后看一看是否需要退出去。</p>
<p>它的结构如下：</p>
<div class="sourceCode" id="cb104"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb104-1" data-line-number="1"><span class="cf">repeat</span> EXPR</a></code></pre></div>
<p>EXPR 指代一个语句块。为了退出 repeat 循环，我们需要借助 break 语句的力量。</p>
<p>下面是一个简单例子：</p>
<div class="sourceCode" id="cb105"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb105-1" data-line-number="1">i &lt;-<span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb105-2" data-line-number="2"></a>
<a class="sourceLine" id="cb105-3" data-line-number="3"><span class="cf">repeat</span>{</a>
<a class="sourceLine" id="cb105-4" data-line-number="4">  <span class="kw">print</span>(i)</a>
<a class="sourceLine" id="cb105-5" data-line-number="5">  i &lt;-<span class="st"> </span>i<span class="op">*</span><span class="dv">2</span></a>
<a class="sourceLine" id="cb105-6" data-line-number="6">  <span class="cf">if</span> (i <span class="op">&gt;</span><span class="st"> </span><span class="dv">100</span>) <span class="cf">break</span></a>
<a class="sourceLine" id="cb105-7" data-line-number="7">}</a>
<a class="sourceLine" id="cb105-8" data-line-number="8"><span class="co">#&gt; [1] 1</span></a>
<a class="sourceLine" id="cb105-9" data-line-number="9"><span class="co">#&gt; [1] 2</span></a>
<a class="sourceLine" id="cb105-10" data-line-number="10"><span class="co">#&gt; [1] 4</span></a>
<a class="sourceLine" id="cb105-11" data-line-number="11"><span class="co">#&gt; [1] 8</span></a>
<a class="sourceLine" id="cb105-12" data-line-number="12"><span class="co">#&gt; [1] 16</span></a>
<a class="sourceLine" id="cb105-13" data-line-number="13"><span class="co">#&gt; [1] 32</span></a>
<a class="sourceLine" id="cb105-14" data-line-number="14"><span class="co">#&gt; [1] 64</span></a></code></pre></div>
<p>break 语句执行后将跳出当前的循环，另有 next 语句，它可以跳过后续代码的运行进入下一次循环。</p>
<p>基于上面的例子我们再构造一个示例：</p>
<div class="sourceCode" id="cb106"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb106-1" data-line-number="1">i &lt;-<span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb106-2" data-line-number="2"></a>
<a class="sourceLine" id="cb106-3" data-line-number="3"><span class="cf">repeat</span>{</a>
<a class="sourceLine" id="cb106-4" data-line-number="4">  <span class="kw">print</span>(i)</a>
<a class="sourceLine" id="cb106-5" data-line-number="5">  i &lt;-<span class="st"> </span>i<span class="op">*</span><span class="dv">2</span></a>
<a class="sourceLine" id="cb106-6" data-line-number="6">  <span class="cf">if</span> (i <span class="op">&gt;</span><span class="st"> </span><span class="dv">200</span>) <span class="cf">break</span>()</a>
<a class="sourceLine" id="cb106-7" data-line-number="7">  <span class="cf">if</span> (i <span class="op">&gt;</span><span class="st"> </span><span class="dv">100</span>) <span class="cf">next</span>()</a>
<a class="sourceLine" id="cb106-8" data-line-number="8">  <span class="kw">print</span>(<span class="st">&quot;Can you see me?&quot;</span>)</a>
<a class="sourceLine" id="cb106-9" data-line-number="9">}</a>
<a class="sourceLine" id="cb106-10" data-line-number="10"><span class="co">#&gt; [1] 1</span></a>
<a class="sourceLine" id="cb106-11" data-line-number="11"><span class="co">#&gt; [1] &quot;Can you see me?&quot;</span></a>
<a class="sourceLine" id="cb106-12" data-line-number="12"><span class="co">#&gt; [1] 2</span></a>
<a class="sourceLine" id="cb106-13" data-line-number="13"><span class="co">#&gt; [1] &quot;Can you see me?&quot;</span></a>
<a class="sourceLine" id="cb106-14" data-line-number="14"><span class="co">#&gt; [1] 4</span></a>
<a class="sourceLine" id="cb106-15" data-line-number="15"><span class="co">#&gt; [1] &quot;Can you see me?&quot;</span></a>
<a class="sourceLine" id="cb106-16" data-line-number="16"><span class="co">#&gt; [1] 8</span></a>
<a class="sourceLine" id="cb106-17" data-line-number="17"><span class="co">#&gt; [1] &quot;Can you see me?&quot;</span></a>
<a class="sourceLine" id="cb106-18" data-line-number="18"><span class="co">#&gt; [1] 16</span></a>
<a class="sourceLine" id="cb106-19" data-line-number="19"><span class="co">#&gt; [1] &quot;Can you see me?&quot;</span></a>
<a class="sourceLine" id="cb106-20" data-line-number="20"><span class="co">#&gt; [1] 32</span></a>
<a class="sourceLine" id="cb106-21" data-line-number="21"><span class="co">#&gt; [1] &quot;Can you see me?&quot;</span></a>
<a class="sourceLine" id="cb106-22" data-line-number="22"><span class="co">#&gt; [1] 64</span></a>
<a class="sourceLine" id="cb106-23" data-line-number="23"><span class="co">#&gt; [1] 128</span></a></code></pre></div>
<p>当 <code>i &gt; 100</code> 后，最后一条输出语句就不再运行。</p>
</div>
</div>
</div>
<div id="函数与函数式编程" class="section level2">
<h2><span class="header-section-number">2.3</span> 函数与函数式编程</h2>
<p><strong>函数是代码模板</strong>。</p>
<p>前面我们使用符号（Symbol）来对数据抽象形成我们所谓的变量，变量名解释了所指向数据的内含但遮掩了底层的结构。类似地，我们也利用符号来对代码块所运行的操作集合进行抽象，并将其称为<strong>函数</strong>。</p>
<ul>
<li>变量 &lt;- 数据。</li>
<li>函数 &lt;- 操作。</li>
</ul>
<p>这样，函数就使得一组操作可以像使用变量那样重复使用了。</p>
<div id="创建和使用函数" class="section level3">
<h3><span class="header-section-number">2.3.1</span> 创建和使用函数</h3>
<p>我们通过自定义一个计算均值的函数来查看函数是如何创建的：</p>
<div class="sourceCode" id="cb107"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb107-1" data-line-number="1">customMean &lt;-<span class="st"> </span><span class="cf">function</span>(x) {  <span class="co"># x 是输入参数</span></a>
<a class="sourceLine" id="cb107-2" data-line-number="2">  </a>
<a class="sourceLine" id="cb107-3" data-line-number="3">  <span class="co"># 以下是操作集合，即代码块</span></a>
<a class="sourceLine" id="cb107-4" data-line-number="4">  s &lt;-<span class="st"> </span>i &lt;-<span class="st"> </span><span class="dv">0</span></a>
<a class="sourceLine" id="cb107-5" data-line-number="5">  <span class="cf">for</span> (j <span class="cf">in</span> x) {</a>
<a class="sourceLine" id="cb107-6" data-line-number="6">    s &lt;-<span class="st"> </span>s <span class="op">+</span><span class="st"> </span>j</a>
<a class="sourceLine" id="cb107-7" data-line-number="7">    i &lt;-<span class="st"> </span>i <span class="op">+</span><span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb107-8" data-line-number="8">  }</a>
<a class="sourceLine" id="cb107-9" data-line-number="9">  </a>
<a class="sourceLine" id="cb107-10" data-line-number="10">  <span class="kw">return</span>(s <span class="op">/</span><span class="st"> </span>i)  <span class="co"># s / i 是返回值</span></a>
<a class="sourceLine" id="cb107-11" data-line-number="11">}</a></code></pre></div>
<p>一个函数包含输入参数、代码块和返回值 3 部分。当函数中没有使用 <code>return()</code> 时，函数默认会返回最后一个表达式的结果，因此上述代码中将 <code>return(s / i)</code> 改为 <code>s / i</code> 是完全一样的，但后者代码逻辑没有前者清楚。</p>
<p>接下来我们看如何使用这个函数。在创建函数时其实我们已经默认假设输入的是一个数值向量，先试试看：</p>
<div class="sourceCode" id="cb108"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb108-1" data-line-number="1"><span class="kw">customMean</span>(<span class="dt">x =</span> <span class="kw">c</span>(<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>))</a>
<a class="sourceLine" id="cb108-2" data-line-number="2"><span class="co">#&gt; [1] 2</span></a></code></pre></div>
<p>结果是对的。</p>
<p>假设我们不仅仅想返回结果，还想要打印计算信息，实现如下新的函数版本：</p>
<div class="sourceCode" id="cb109"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb109-1" data-line-number="1">customMean_v2 &lt;-<span class="st"> </span><span class="cf">function</span>(x) {  </a>
<a class="sourceLine" id="cb109-2" data-line-number="2">  </a>
<a class="sourceLine" id="cb109-3" data-line-number="3">  s &lt;-<span class="st"> </span>i &lt;-<span class="st"> </span><span class="dv">0</span></a>
<a class="sourceLine" id="cb109-4" data-line-number="4">  <span class="cf">for</span> (j <span class="cf">in</span> x) {</a>
<a class="sourceLine" id="cb109-5" data-line-number="5">    s &lt;-<span class="st"> </span>s <span class="op">+</span><span class="st"> </span>j</a>
<a class="sourceLine" id="cb109-6" data-line-number="6">    i &lt;-<span class="st"> </span>i <span class="op">+</span><span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb109-7" data-line-number="7">  }</a>
<a class="sourceLine" id="cb109-8" data-line-number="8">  </a>
<a class="sourceLine" id="cb109-9" data-line-number="9">  mu &lt;-<span class="st"> </span>s <span class="op">/</span><span class="st"> </span>i</a>
<a class="sourceLine" id="cb109-10" data-line-number="10">  </a>
<a class="sourceLine" id="cb109-11" data-line-number="11">  <span class="kw">message</span>(</a>
<a class="sourceLine" id="cb109-12" data-line-number="12">    <span class="st">&quot;Mean of sequence &quot;</span>,</a>
<a class="sourceLine" id="cb109-13" data-line-number="13">    <span class="kw">paste</span>(x, <span class="dt">collapse =</span> <span class="st">&quot;,&quot;</span>),</a>
<a class="sourceLine" id="cb109-14" data-line-number="14">    <span class="st">&quot; is &quot;</span>,</a>
<a class="sourceLine" id="cb109-15" data-line-number="15">    mu</a>
<a class="sourceLine" id="cb109-16" data-line-number="16">  )</a>
<a class="sourceLine" id="cb109-17" data-line-number="17">  </a>
<a class="sourceLine" id="cb109-18" data-line-number="18">  <span class="kw">return</span>(mu)  </a>
<a class="sourceLine" id="cb109-19" data-line-number="19">}</a></code></pre></div>
<p>再来看下结果：</p>
<div class="sourceCode" id="cb110"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb110-1" data-line-number="1"><span class="kw">customMean_v2</span>(<span class="dt">x =</span> <span class="kw">c</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">3</span>))</a>
<a class="sourceLine" id="cb110-2" data-line-number="2"><span class="co">#&gt; Mean of sequence 1,2,3 is 2</span></a>
<a class="sourceLine" id="cb110-3" data-line-number="3"><span class="co">#&gt; [1] 2</span></a></code></pre></div>
<p>这样结果看起来更加人性化了。但仔细思考一下，更新后的函数引入了新的问题：如果有 10000 个数字相加，这样打印信息还是一件好事吗？</p>
<p>我们不妨再引入一个新的函数版本，这个版本处理打印以及如何打印的问题：</p>
<div class="sourceCode" id="cb111"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb111-1" data-line-number="1">customMean_v3 &lt;-<span class="st"> </span><span class="cf">function</span>(x, <span class="dt">verbose =</span> <span class="ot">TRUE</span>) {  </a>
<a class="sourceLine" id="cb111-2" data-line-number="2">  </a>
<a class="sourceLine" id="cb111-3" data-line-number="3">  s &lt;-<span class="st"> </span>i &lt;-<span class="st"> </span><span class="dv">0</span></a>
<a class="sourceLine" id="cb111-4" data-line-number="4">  <span class="cf">for</span> (j <span class="cf">in</span> x) {</a>
<a class="sourceLine" id="cb111-5" data-line-number="5">    s &lt;-<span class="st"> </span>s <span class="op">+</span><span class="st"> </span>j</a>
<a class="sourceLine" id="cb111-6" data-line-number="6">    i &lt;-<span class="st"> </span>i <span class="op">+</span><span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb111-7" data-line-number="7">  }</a>
<a class="sourceLine" id="cb111-8" data-line-number="8">  </a>
<a class="sourceLine" id="cb111-9" data-line-number="9">  mu &lt;-<span class="st"> </span>s <span class="op">/</span><span class="st"> </span>i</a>
<a class="sourceLine" id="cb111-10" data-line-number="10">  </a>
<a class="sourceLine" id="cb111-11" data-line-number="11">  <span class="cf">if</span> (verbose) {</a>
<a class="sourceLine" id="cb111-12" data-line-number="12">    l &lt;-<span class="st"> </span><span class="kw">length</span>(x)</a>
<a class="sourceLine" id="cb111-13" data-line-number="13">    <span class="cf">if</span> (l <span class="op">&gt;</span><span class="st"> </span><span class="dv">10</span>) {</a>
<a class="sourceLine" id="cb111-14" data-line-number="14">      <span class="kw">message</span>(</a>
<a class="sourceLine" id="cb111-15" data-line-number="15">        <span class="st">&quot;Mean of sequence &quot;</span>,</a>
<a class="sourceLine" id="cb111-16" data-line-number="16">        <span class="kw">paste</span>(<span class="kw">c</span>(x[<span class="dv">1</span><span class="op">:</span><span class="dv">5</span>], <span class="st">&quot;...&quot;</span>, x[(l<span class="dv">-4</span>)<span class="op">:</span>l]), <span class="dt">collapse =</span> <span class="st">&quot;,&quot;</span>),</a>
<a class="sourceLine" id="cb111-17" data-line-number="17">        <span class="st">&quot; is &quot;</span>,</a>
<a class="sourceLine" id="cb111-18" data-line-number="18">        mu</a>
<a class="sourceLine" id="cb111-19" data-line-number="19">      )</a>
<a class="sourceLine" id="cb111-20" data-line-number="20">    } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb111-21" data-line-number="21">      <span class="kw">message</span>(</a>
<a class="sourceLine" id="cb111-22" data-line-number="22">        <span class="st">&quot;Mean of sequence &quot;</span>,</a>
<a class="sourceLine" id="cb111-23" data-line-number="23">        <span class="kw">paste</span>(x, <span class="dt">collapse =</span> <span class="st">&quot;,&quot;</span>),</a>
<a class="sourceLine" id="cb111-24" data-line-number="24">        <span class="st">&quot; is &quot;</span>,</a>
<a class="sourceLine" id="cb111-25" data-line-number="25">        mu</a>
<a class="sourceLine" id="cb111-26" data-line-number="26">      )</a>
<a class="sourceLine" id="cb111-27" data-line-number="27">    }</a>
<a class="sourceLine" id="cb111-28" data-line-number="28">  }</a>
<a class="sourceLine" id="cb111-29" data-line-number="29">  </a>
<a class="sourceLine" id="cb111-30" data-line-number="30">  <span class="kw">return</span>(mu)  </a>
<a class="sourceLine" id="cb111-31" data-line-number="31">}</a></code></pre></div>
<p>我们用这个函数试一下输入少或多的情况。</p>
<div class="sourceCode" id="cb112"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb112-1" data-line-number="1"><span class="kw">customMean_v3</span>(<span class="dt">x =</span> <span class="dv">1</span><span class="op">:</span><span class="dv">10</span>)</a>
<a class="sourceLine" id="cb112-2" data-line-number="2"><span class="co">#&gt; Mean of sequence 1,2,3,4,5,6,7,8,9,10 is 5.5</span></a>
<a class="sourceLine" id="cb112-3" data-line-number="3"><span class="co">#&gt; [1] 5.5</span></a>
<a class="sourceLine" id="cb112-4" data-line-number="4"><span class="kw">customMean_v3</span>(<span class="dt">x =</span> <span class="dv">1</span><span class="op">:</span><span class="dv">100</span>)</a>
<a class="sourceLine" id="cb112-5" data-line-number="5"><span class="co">#&gt; Mean of sequence 1,2,3,4,5,...,96,97,98,99,100 is 50.5</span></a>
<a class="sourceLine" id="cb112-6" data-line-number="6"><span class="co">#&gt; [1] 50.5</span></a></code></pre></div>
<p>除此之外，我们在新的版本中引入了一个默认参数 <code>verbose</code>，我们可以选择不打印信息：</p>
<div class="sourceCode" id="cb113"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb113-1" data-line-number="1"><span class="kw">customMean_v3</span>(<span class="dt">x =</span> <span class="dv">1</span><span class="op">:</span><span class="dv">100</span>, <span class="dt">verbose =</span> <span class="ot">FALSE</span>)</a>
<a class="sourceLine" id="cb113-2" data-line-number="2"><span class="co">#&gt; [1] 50.5</span></a></code></pre></div>
<p>当按顺序输入函数参数时，参数的名称是可以不输入的，下面的结果一致：</p>
<div class="sourceCode" id="cb114"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb114-1" data-line-number="1"><span class="kw">customMean_v3</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">100</span>, <span class="ot">FALSE</span>)</a>
<a class="sourceLine" id="cb114-2" data-line-number="2"><span class="co">#&gt; [1] 50.5</span></a></code></pre></div>
<p>以上的输入都是基于函数使用者很清楚的知道输入是一个数值型向量，有时候这一点很难做到。例如，你将代码发送给一位不懂编程的人员使用。此时，添加参数检查和注释是有必要的，我们由此创建一个新的函数版本：</p>
<div class="sourceCode" id="cb115"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb115-1" data-line-number="1"><span class="co"># @title 计算均值</span></a>
<a class="sourceLine" id="cb115-2" data-line-number="2"><span class="co"># @param x 输入数据，一个数值向量</span></a>
<a class="sourceLine" id="cb115-3" data-line-number="3"><span class="co"># @param verbose 逻辑值，控制是否打印</span></a>
<a class="sourceLine" id="cb115-4" data-line-number="4">customMean_v4 &lt;-<span class="st"> </span><span class="cf">function</span>(x, <span class="dt">verbose =</span> <span class="ot">TRUE</span>) {  </a>
<a class="sourceLine" id="cb115-5" data-line-number="5">  </a>
<a class="sourceLine" id="cb115-6" data-line-number="6">  <span class="cf">if</span> (<span class="op">!</span><span class="kw">is.numeric</span>(x)) {</a>
<a class="sourceLine" id="cb115-7" data-line-number="7">    <span class="kw">stop</span>(<span class="st">&quot;输入数据必须是一个数值型向量！&quot;</span>)</a>
<a class="sourceLine" id="cb115-8" data-line-number="8">  }</a>
<a class="sourceLine" id="cb115-9" data-line-number="9">  </a>
<a class="sourceLine" id="cb115-10" data-line-number="10">  s &lt;-<span class="st"> </span>i &lt;-<span class="st"> </span><span class="dv">0</span></a>
<a class="sourceLine" id="cb115-11" data-line-number="11">  <span class="cf">for</span> (j <span class="cf">in</span> x) {</a>
<a class="sourceLine" id="cb115-12" data-line-number="12">    s &lt;-<span class="st"> </span>s <span class="op">+</span><span class="st"> </span>j</a>
<a class="sourceLine" id="cb115-13" data-line-number="13">    i &lt;-<span class="st"> </span>i <span class="op">+</span><span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb115-14" data-line-number="14">  }</a>
<a class="sourceLine" id="cb115-15" data-line-number="15">  </a>
<a class="sourceLine" id="cb115-16" data-line-number="16">  mu &lt;-<span class="st"> </span>s <span class="op">/</span><span class="st"> </span>i</a>
<a class="sourceLine" id="cb115-17" data-line-number="17">  </a>
<a class="sourceLine" id="cb115-18" data-line-number="18">  <span class="cf">if</span> (verbose) {</a>
<a class="sourceLine" id="cb115-19" data-line-number="19">    l &lt;-<span class="st"> </span><span class="kw">length</span>(x)</a>
<a class="sourceLine" id="cb115-20" data-line-number="20">    <span class="cf">if</span> (l <span class="op">&gt;</span><span class="st"> </span><span class="dv">10</span>) {</a>
<a class="sourceLine" id="cb115-21" data-line-number="21">      <span class="kw">message</span>(</a>
<a class="sourceLine" id="cb115-22" data-line-number="22">        <span class="st">&quot;Mean of sequence &quot;</span>,</a>
<a class="sourceLine" id="cb115-23" data-line-number="23">        <span class="kw">paste</span>(<span class="kw">c</span>(x[<span class="dv">1</span><span class="op">:</span><span class="dv">5</span>], <span class="st">&quot;...&quot;</span>, x[(l<span class="dv">-4</span>)<span class="op">:</span>l]), <span class="dt">collapse =</span> <span class="st">&quot;,&quot;</span>),</a>
<a class="sourceLine" id="cb115-24" data-line-number="24">        <span class="st">&quot; is &quot;</span>,</a>
<a class="sourceLine" id="cb115-25" data-line-number="25">        mu</a>
<a class="sourceLine" id="cb115-26" data-line-number="26">      )</a>
<a class="sourceLine" id="cb115-27" data-line-number="27">    } <span class="cf">else</span> {</a>
<a class="sourceLine" id="cb115-28" data-line-number="28">      <span class="kw">message</span>(</a>
<a class="sourceLine" id="cb115-29" data-line-number="29">        <span class="st">&quot;Mean of sequence &quot;</span>,</a>
<a class="sourceLine" id="cb115-30" data-line-number="30">        <span class="kw">paste</span>(x, <span class="dt">collapse =</span> <span class="st">&quot;,&quot;</span>),</a>
<a class="sourceLine" id="cb115-31" data-line-number="31">        <span class="st">&quot; is &quot;</span>,</a>
<a class="sourceLine" id="cb115-32" data-line-number="32">        mu</a>
<a class="sourceLine" id="cb115-33" data-line-number="33">      )</a>
<a class="sourceLine" id="cb115-34" data-line-number="34">    }</a>
<a class="sourceLine" id="cb115-35" data-line-number="35">  }</a>
<a class="sourceLine" id="cb115-36" data-line-number="36">  </a>
<a class="sourceLine" id="cb115-37" data-line-number="37">  <span class="kw">return</span>(mu)  </a>
<a class="sourceLine" id="cb115-38" data-line-number="38">}</a></code></pre></div>
<p>以<code>#</code> 开始的文本被 R 认为是一个代码注释，后续 <code>@title</code> 和 <code>@param</code> 是注释标签，这些是<strong>非必需</strong>的，它只是用来更好地描述注释的内容。</p>
<blockquote>
<p>代码标签符合 <strong>roxygen2</strong> 包的定义，有兴趣的读者可以看一看这个包文档。</p>
</blockquote>
<div class="sourceCode" id="cb116"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb116-1" data-line-number="1"><span class="kw">customMean_v4</span>(<span class="kw">c</span>(<span class="st">&quot;1&quot;</span>, <span class="st">&quot;2&quot;</span>, <span class="st">&quot;3&quot;</span>))</a>
<a class="sourceLine" id="cb116-2" data-line-number="2"><span class="co">#&gt; Error in customMean_v4(c(&quot;1&quot;, &quot;2&quot;, &quot;3&quot;)): 输入数据必须是一个数值型向量！</span></a></code></pre></div>
<p>最后，我们来了解一下函数的计算效率。这里我们将创建的 <code>customMean()</code> 函数与 R 内置的 <code>mean()</code> 函数进行对比。<code>system.time()</code> 函数用来判断函数执行消耗的时间。</p>
<div class="sourceCode" id="cb117"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb117-1" data-line-number="1"><span class="kw">system.time</span>(<span class="kw">customMean</span>(<span class="dv">1</span><span class="op">:</span><span class="fl">1e7</span>))</a>
<a class="sourceLine" id="cb117-2" data-line-number="2"><span class="co">#&gt;  用户  系统  流逝 </span></a>
<a class="sourceLine" id="cb117-3" data-line-number="3"><span class="co">#&gt; 0.280 0.001 0.283</span></a>
<a class="sourceLine" id="cb117-4" data-line-number="4"><span class="kw">system.time</span>(<span class="kw">mean</span>(<span class="dv">1</span><span class="op">:</span><span class="fl">1e7</span>))</a>
<a class="sourceLine" id="cb117-5" data-line-number="5"><span class="co">#&gt;  用户  系统  流逝 </span></a>
<a class="sourceLine" id="cb117-6" data-line-number="6"><span class="co">#&gt; 0.047 0.000 0.047</span></a></code></pre></div>
<p><code>elapsed</code> 项给出了计算机执行函数消耗的总时间（以秒为单位），可以看出，内置的函数还是要快很多的。当然，这并不是一个严格的性能测评，但它已经能清楚地表明两者的差距。</p>
</div>
<div id="作用域" class="section level3">
<h3><span class="header-section-number">2.3.2</span> 作用域</h3>
<p>每个函数都有它的领地，更专业地说，当一个函数被创建后，R 中存在一个让这个函数发挥作用的环境。举一个比较形象的例子，冬天我们在购物商场外常常感到寒冷，而进去之后会感到暖和，这是因为商场空调的作用范围只是整个商场。</p>
<p>R 中所有的对象都处于各自的环境之中，我们可以把环境想象成城市里各种不同房子，而对象是处于其中的物品。当然这只是一些形象的比喻，实际上 R 的工作原理可能远不仅如此，但它已经能够很好地帮助理解我们这个概念了。</p>
<p>在启动 R 之后，我们就进去了一个全局环境之中（Global Environment），我们创建的各自变量、函数都会处于其中。这一点我们可以轻易地从 RStudio 右上角的环境窗口中观察到，如图 <a href="base.html#fig:rstudio-env-panel">2.4</a> 所示：</p>
<div class="figure" style="text-align: center"><span id="fig:rstudio-env-panel"></span>
<img src="fig/ch02-rstudio-env-panel.PNG" alt="RStudio 的环境窗口"  />
<p class="caption">
图 2.4: RStudio 的环境窗口
</p>
</div>
<p>一个函数（如 <code>customMean()</code>）与全局环境的关系可以简单用下面两个嵌套的矩形表示：</p>
<div class="figure" style="text-align: center"><span id="fig:fun-env"></span>
<img src="fig/ch02-fun-env.png" alt="全局环境与在其中创建的一个函数"  />
<p class="caption">
图 2.5: 全局环境与在其中创建的一个函数
</p>
</div>
<p>我使用了蓝色箭头来表示两者的从属关系，先有全局环境，再有函数环境。我使用绿色箭头表示函数查询变量的方向，先从自己内部查找，如果找不到，再从外部查找。</p>
<p>前面我们创建的函数内部都是自给自足的，下面我们创建一个不一样的。</p>
<div class="sourceCode" id="cb118"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb118-1" data-line-number="1">a &lt;-<span class="st"> </span><span class="dv">3</span></a>
<a class="sourceLine" id="cb118-2" data-line-number="2">Sum &lt;-<span class="st"> </span><span class="cf">function</span>(b) {</a>
<a class="sourceLine" id="cb118-3" data-line-number="3">  a <span class="op">+</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb118-4" data-line-number="4">}</a></code></pre></div>
<p>我在函数 <code>Sum()</code> 之外创建了一个变量 <code>a</code>，而函数内部并没有创建相同名字的变量，这样的函数能够成功调用吗？</p>
<p>我们试试。</p>
<div class="sourceCode" id="cb119"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb119-1" data-line-number="1"><span class="kw">Sum</span>(<span class="dv">10</span>)</a>
<a class="sourceLine" id="cb119-2" data-line-number="2"><span class="co">#&gt; [1] 13</span></a></code></pre></div>
<p>结果显示是当然可行的。也就是说，<strong>当函数在自身内部无法查询到变量 <code>a</code> 的值时，它会向外面一层寻找</strong>。事实上，如果在外层还找不到，而且外层环境如果也处于另一个环境之中，它会再次往外面一层查找。如果按照这个规则真的都找不到，R 就会抛出错误。</p>
<div class="sourceCode" id="cb120"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb120-1" data-line-number="1">zzzz</a>
<a class="sourceLine" id="cb120-2" data-line-number="2"><span class="co">#&gt; Error in eval(expr, envir, enclos): 找不到对象&#39;zzzz&#39;</span></a></code></pre></div>
<p>如果函数内部存在一个同名变量会怎么样呢？如果读者理解了上面我介绍的规则，那么应该不难猜到下面变量 <code>result</code> 保存的值。</p>
<div class="sourceCode" id="cb121"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb121-1" data-line-number="1">a &lt;-<span class="st"> </span><span class="dv">3</span></a>
<a class="sourceLine" id="cb121-2" data-line-number="2">Sum &lt;-<span class="st"> </span><span class="cf">function</span>(b) {</a>
<a class="sourceLine" id="cb121-3" data-line-number="3">  a &lt;-<span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb121-4" data-line-number="4">  a <span class="op">+</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb121-5" data-line-number="5">}</a>
<a class="sourceLine" id="cb121-6" data-line-number="6"></a>
<a class="sourceLine" id="cb121-7" data-line-number="7">result &lt;-<span class="st"> </span><span class="kw">Sum</span>(<span class="dv">10</span>)</a></code></pre></div>
<p>下面揭晓答案：</p>
<div class="sourceCode" id="cb122"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb122-1" data-line-number="1">result</a>
<a class="sourceLine" id="cb122-2" data-line-number="2"><span class="co">#&gt; [1] 11</span></a></code></pre></div>
<p>在某些情景下，我们可能需要在函数内部修改函数外部变量的值。此时我们可以引入新的操作符 <code>&lt;&lt;-</code>，我们简单修改上面的代码看看 全局变量 <code>a</code> 变成了什么。</p>
<div class="sourceCode" id="cb123"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb123-1" data-line-number="1">a &lt;-<span class="st"> </span><span class="dv">3</span></a>
<a class="sourceLine" id="cb123-2" data-line-number="2"><span class="co"># 运行函数之前</span></a>
<a class="sourceLine" id="cb123-3" data-line-number="3">a</a>
<a class="sourceLine" id="cb123-4" data-line-number="4"><span class="co">#&gt; [1] 3</span></a>
<a class="sourceLine" id="cb123-5" data-line-number="5"></a>
<a class="sourceLine" id="cb123-6" data-line-number="6">Sum &lt;-<span class="st"> </span><span class="cf">function</span>(b) {</a>
<a class="sourceLine" id="cb123-7" data-line-number="7">  a &lt;&lt;-<span class="st"> </span><span class="dv">1</span></a>
<a class="sourceLine" id="cb123-8" data-line-number="8">  a <span class="op">+</span><span class="st"> </span>b</a>
<a class="sourceLine" id="cb123-9" data-line-number="9">}</a>
<a class="sourceLine" id="cb123-10" data-line-number="10"></a>
<a class="sourceLine" id="cb123-11" data-line-number="11">result &lt;-<span class="st"> </span><span class="kw">Sum</span>(<span class="dv">10</span>)</a>
<a class="sourceLine" id="cb123-12" data-line-number="12"><span class="co"># 运行函数之后</span></a>
<a class="sourceLine" id="cb123-13" data-line-number="13">a</a>
<a class="sourceLine" id="cb123-14" data-line-number="14"><span class="co">#&gt; [1] 1</span></a></code></pre></div>
</div>
<div id="任意参数" class="section level3">
<h3><span class="header-section-number">2.3.3</span> 任意参数</h3>
<p>我们在 R 中可能会经常看到函数的参数中有 <code>...</code> 这样的符号，它代表可以传入任意长度的参数。</p>
<p>例如，我们利用它构造一个可以求取任意个参数之和的函数：</p>
<div class="sourceCode" id="cb124"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb124-1" data-line-number="1">addAll &lt;-<span class="st"> </span><span class="cf">function</span>(x, ...) {</a>
<a class="sourceLine" id="cb124-2" data-line-number="2">  args &lt;-<span class="st"> </span><span class="kw">list</span>(...)</a>
<a class="sourceLine" id="cb124-3" data-line-number="3">  <span class="cf">for</span> (a <span class="cf">in</span> args) {</a>
<a class="sourceLine" id="cb124-4" data-line-number="4">    x &lt;-<span class="st"> </span>x <span class="op">+</span><span class="st"> </span>a</a>
<a class="sourceLine" id="cb124-5" data-line-number="5">  }</a>
<a class="sourceLine" id="cb124-6" data-line-number="6">  <span class="kw">return</span>(x)</a>
<a class="sourceLine" id="cb124-7" data-line-number="7">}</a></code></pre></div>
<p>试一试效果：</p>
<div class="sourceCode" id="cb125"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb125-1" data-line-number="1"><span class="kw">addAll</span>(<span class="dv">1</span>, <span class="dv">2</span>, <span class="dv">3</span>)</a>
<a class="sourceLine" id="cb125-2" data-line-number="2"><span class="co">#&gt; [1] 6</span></a>
<a class="sourceLine" id="cb125-3" data-line-number="3"><span class="kw">addAll</span>(<span class="dv">3</span>, <span class="dv">4</span>, <span class="dv">5</span>, <span class="dv">6</span>, <span class="dv">7</span>, <span class="dv">8</span>)</a>
<a class="sourceLine" id="cb125-4" data-line-number="4"><span class="co">#&gt; [1] 33</span></a></code></pre></div>
<p>函数中我们使用了 <code>list()</code> 将传入的 <code>...</code> 转换为列表，然后再进行处理。除此之外，我们还可以直接使用 <code>..1</code>、<code>..2</code> 等直接引用 <code>...</code> 对象中的第 1 个元素、第 2 个元素。</p>
</div>
<div id="函数式编程" class="section level3">
<h3><span class="header-section-number">2.3.4</span> 函数式编程</h3>
<p>函数不仅仅可以被调用，<strong>它还可以被当作函数的参数和返回值</strong>，这是函数式编程的特点。</p>
<div id="传入和返回函数" class="section level4">
<h4><span class="header-section-number">2.3.4.1</span> 传入和返回函数</h4>
<p>例如，我们创建一个略显奇怪的函数：</p>
<div class="sourceCode" id="cb126"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb126-1" data-line-number="1">f &lt;-<span class="st"> </span><span class="cf">function</span>(x, fun) {</a>
<a class="sourceLine" id="cb126-2" data-line-number="2">  <span class="kw">fun</span>(x)</a>
<a class="sourceLine" id="cb126-3" data-line-number="3">}</a></code></pre></div>
<p>它可以将常见的数值计算函数作为参数计算相应的结果，在讲解之前我们先看看效果：</p>
<div class="sourceCode" id="cb127"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb127-1" data-line-number="1"><span class="kw">f</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">10</span>, sum)</a>
<a class="sourceLine" id="cb127-2" data-line-number="2"><span class="co">#&gt; [1] 55</span></a>
<a class="sourceLine" id="cb127-3" data-line-number="3"><span class="kw">f</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">10</span>, mean)</a>
<a class="sourceLine" id="cb127-4" data-line-number="4"><span class="co">#&gt; [1] 5.5</span></a>
<a class="sourceLine" id="cb127-5" data-line-number="5"><span class="kw">f</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">10</span>, quantile)</a>
<a class="sourceLine" id="cb127-6" data-line-number="6"><span class="co">#&gt;    0%   25%   50%   75%  100% </span></a>
<a class="sourceLine" id="cb127-7" data-line-number="7"><span class="co">#&gt;  1.00  3.25  5.50  7.75 10.00</span></a></code></pre></div>
<p>不难理解，上述代码中发挥计算功效的是函数的第 2 个参数。在我们创建的函数 <code>f()</code> 中，我们可以理解为对传入函数的 <code>mean()</code>、<code>sum()</code> 等函数重命名成 <code>fun()</code> 并进行调用。</p>
<p>我们还可以构建一个函数作为返回值的例子：</p>
<div class="sourceCode" id="cb128"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb128-1" data-line-number="1">f2 &lt;-<span class="st"> </span><span class="cf">function</span>(type) {</a>
<a class="sourceLine" id="cb128-2" data-line-number="2">  <span class="cf">switch</span>(type,</a>
<a class="sourceLine" id="cb128-3" data-line-number="3">         <span class="dt">mean =</span> mean,</a>
<a class="sourceLine" id="cb128-4" data-line-number="4">         <span class="dt">sum =</span> sum,</a>
<a class="sourceLine" id="cb128-5" data-line-number="5">         <span class="dt">quantile =</span> quantile)</a>
<a class="sourceLine" id="cb128-6" data-line-number="6">}</a></code></pre></div>
<p><code>f()</code> 函数使用了 switch 语句，如果使用 if-else 语句实现该函数也是可以的（读者不妨一试），但此处 switch 让代码更加简明。</p>
<p>下面看看效果：</p>
<div class="sourceCode" id="cb129"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb129-1" data-line-number="1"><span class="kw">f2</span>(<span class="st">&quot;mean&quot;</span>)</a>
<a class="sourceLine" id="cb129-2" data-line-number="2"><span class="co">#&gt; function (x, ...) </span></a>
<a class="sourceLine" id="cb129-3" data-line-number="3"><span class="co">#&gt; UseMethod(&quot;mean&quot;)</span></a>
<a class="sourceLine" id="cb129-4" data-line-number="4"><span class="co">#&gt; &lt;bytecode: 0x7ff794a58e00&gt;</span></a>
<a class="sourceLine" id="cb129-5" data-line-number="5"><span class="co">#&gt; &lt;environment: namespace:base&gt;</span></a>
<a class="sourceLine" id="cb129-6" data-line-number="6"><span class="kw">f2</span>(<span class="st">&quot;sum&quot;</span>)</a>
<a class="sourceLine" id="cb129-7" data-line-number="7"><span class="co">#&gt; function (..., na.rm = FALSE)  .Primitive(&quot;sum&quot;)</span></a>
<a class="sourceLine" id="cb129-8" data-line-number="8"><span class="kw">f2</span>(<span class="st">&quot;quantile&quot;</span>)</a>
<a class="sourceLine" id="cb129-9" data-line-number="9"><span class="co">#&gt; function (x, ...) </span></a>
<a class="sourceLine" id="cb129-10" data-line-number="10"><span class="co">#&gt; UseMethod(&quot;quantile&quot;)</span></a>
<a class="sourceLine" id="cb129-11" data-line-number="11"><span class="co">#&gt; &lt;bytecode: 0x7ff794b2c9e0&gt;</span></a>
<a class="sourceLine" id="cb129-12" data-line-number="12"><span class="co">#&gt; &lt;environment: namespace:stats&gt;</span></a></code></pre></div>
<p>返回的全部都是函数，那么我们是不是可以直接调用它呢？</p>
<div class="sourceCode" id="cb130"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb130-1" data-line-number="1"><span class="kw">f2</span>(<span class="st">&quot;mean&quot;</span>)(<span class="dv">1</span><span class="op">:</span><span class="dv">10</span>)</a>
<a class="sourceLine" id="cb130-2" data-line-number="2"><span class="co">#&gt; [1] 5.5</span></a></code></pre></div>
<p>事实证明是可以的。</p>
<p>虽然上面只是通过 2 段简单的代码展示函数式编程的特性，但不难想象到它给 R 语言编程赋予了更多的灵活性。</p>
</div>
<div id="apply-家族" class="section level4">
<h4><span class="header-section-number">2.3.4.2</span> apply 家族</h4>
<p>apply 函数家族包括 <code>apply()</code>、<code>lapply()</code>、<code>sapply()</code> 和 <code>vapply()</code> 等成员，其中前三者比较常用。apply 函数家族正是以函数作为输入来进行批量计算，因此它可以取代我们之前学习的循环控制。</p>
<div id="apply" class="section level5">
<h5><span class="header-section-number">2.3.4.2.1</span> apply</h5>
<p><code>apply()</code> 最常用，针对的也是最常见的表格型数据，在 R 中为矩阵或数据框。</p>
<p>为了展示它的用法和效率，这里我先构造一个 100 列 100,000 行的服从正态分布的数据矩阵：</p>
<div class="sourceCode" id="cb131"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb131-1" data-line-number="1"><span class="co"># 设置随机种子数</span></a>
<a class="sourceLine" id="cb131-2" data-line-number="2"><span class="kw">set.seed</span>(<span class="dv">1234</span>)</a>
<a class="sourceLine" id="cb131-3" data-line-number="3">mat &lt;-<span class="st"> </span><span class="kw">matrix</span>(<span class="kw">rnorm</span>(<span class="fl">1e7</span>), <span class="dt">ncol =</span> <span class="dv">100</span>, <span class="dt">byrow =</span> <span class="ot">TRUE</span>)</a>
<a class="sourceLine" id="cb131-4" data-line-number="4"><span class="co"># 展示数据维度</span></a>
<a class="sourceLine" id="cb131-5" data-line-number="5"><span class="kw">dim</span>(mat)</a>
<a class="sourceLine" id="cb131-6" data-line-number="6"><span class="co">#&gt; [1] 100000    100</span></a>
<a class="sourceLine" id="cb131-7" data-line-number="7"><span class="co"># 查看少量数据</span></a>
<a class="sourceLine" id="cb131-8" data-line-number="8">mat[<span class="dv">1</span><span class="op">:</span><span class="dv">5</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">5</span>]</a>
<a class="sourceLine" id="cb131-9" data-line-number="9"><span class="co">#&gt;         [,1]     [,2]     [,3]    [,4]     [,5]</span></a>
<a class="sourceLine" id="cb131-10" data-line-number="10"><span class="co">#&gt; [1,] -1.2071  0.27743  1.08444 -2.3457  0.42912</span></a>
<a class="sourceLine" id="cb131-11" data-line-number="11"><span class="co">#&gt; [2,]  0.4145 -0.47472  0.06599 -0.5025 -0.82600</span></a>
<a class="sourceLine" id="cb131-12" data-line-number="12"><span class="co">#&gt; [3,]  0.4852  0.69677  0.18551  0.7007  0.31168</span></a>
<a class="sourceLine" id="cb131-13" data-line-number="13"><span class="co">#&gt; [4,] -0.5800 -0.95328 -0.17943  1.0098  0.02363</span></a>
<a class="sourceLine" id="cb131-14" data-line-number="14"><span class="co">#&gt; [5,] -1.2268  0.03615 -0.42139 -0.8994  0.41744</span></a></code></pre></div>
<p>现在如果我们想要计算每一行的均值，该怎么实现呢（不使用 <code>rowMeans()</code> 函数）？</p>
<p>先试试使用之前学习的 for 循环构建一个计算函数：</p>
<div class="sourceCode" id="cb132"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb132-1" data-line-number="1">calcRowMeans &lt;-<span class="st"> </span><span class="cf">function</span>(mat) {</a>
<a class="sourceLine" id="cb132-2" data-line-number="2">  <span class="co"># 先初始化一个结果向量</span></a>
<a class="sourceLine" id="cb132-3" data-line-number="3">  <span class="co"># 这样更有效率</span></a>
<a class="sourceLine" id="cb132-4" data-line-number="4">  res &lt;-<span class="st"> </span><span class="kw">vector</span>(<span class="st">&quot;numeric&quot;</span>, <span class="kw">nrow</span>(mat))</a>
<a class="sourceLine" id="cb132-5" data-line-number="5">  <span class="cf">for</span> (i <span class="cf">in</span> <span class="dv">1</span><span class="op">:</span><span class="kw">nrow</span>(mat)) {</a>
<a class="sourceLine" id="cb132-6" data-line-number="6">    res[i] &lt;-<span class="st"> </span><span class="kw">mean</span>(mat[i, ])</a>
<a class="sourceLine" id="cb132-7" data-line-number="7">  }</a>
<a class="sourceLine" id="cb132-8" data-line-number="8">  </a>
<a class="sourceLine" id="cb132-9" data-line-number="9">  <span class="kw">return</span>(res)</a>
<a class="sourceLine" id="cb132-10" data-line-number="10">} </a></code></pre></div>
<p>看一下该函数的用时：</p>
<div class="sourceCode" id="cb133"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb133-1" data-line-number="1"><span class="kw">system.time</span>(</a>
<a class="sourceLine" id="cb133-2" data-line-number="2">  rm &lt;-<span class="st"> </span><span class="kw">calcRowMeans</span>(mat)</a>
<a class="sourceLine" id="cb133-3" data-line-number="3">)</a>
<a class="sourceLine" id="cb133-4" data-line-number="4"><span class="co">#&gt;  用户  系统  流逝 </span></a>
<a class="sourceLine" id="cb133-5" data-line-number="5"><span class="co">#&gt; 0.456 0.032 0.492</span></a></code></pre></div>
<p>10 万行的过程花了不到 1 秒的时间，计算效率着实不低。如果是 <code>apply()</code> 该怎么写呢？效率又如何？</p>
<div class="sourceCode" id="cb134"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb134-1" data-line-number="1"><span class="kw">system.time</span>(</a>
<a class="sourceLine" id="cb134-2" data-line-number="2">  rm &lt;-<span class="st"> </span><span class="kw">apply</span>(mat, <span class="dv">1</span>, mean)</a>
<a class="sourceLine" id="cb134-3" data-line-number="3">)</a>
<a class="sourceLine" id="cb134-4" data-line-number="4"><span class="co">#&gt;  用户  系统  流逝 </span></a>
<a class="sourceLine" id="cb134-5" data-line-number="5"><span class="co">#&gt; 0.503 0.038 0.541</span></a></code></pre></div>
<p>在 apply 写法中，我们没有新建函数，而是直接利用 R 内置的 <code>mean()</code> 函数直接进行计算，相比 for 循环此处的计算效率虽然未见明显提升，但代码却被极度精简了。</p>
<p>让我们来看一下 <code>apply()</code> 是如何完成计算的，其结构如下：</p>
<div class="sourceCode" id="cb135"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb135-1" data-line-number="1"><span class="kw">apply</span>(X, MARGIN, FUN, ...)</a></code></pre></div>
<p>第 1 个参数是数组（可以是矩阵和数据框），第 2 个参数是设置按行（设为 <code>1</code>）或列（设为 <code>2</code>）逐行取子集，第 3 个参数是对子集调用的函数，接下来是传入函数 <code>FUN</code> 中的可选参数列表。前 3 个参数最关键。</p>
<p>因此，在 <code>rm &lt;- apply(mat, 1, mean)</code> 中 <code>apply()</code> 所做的是<strong>逐行提取矩阵 <code>mat</code> 的值并传入函数 <code>mean()</code>进行 计算，然后返回结果</strong>。</p>
<p>利用 <code>apply()</code> 我们可以抛弃 for 循环对矩阵按行按列各种运算：</p>
<div class="sourceCode" id="cb136"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb136-1" data-line-number="1"><span class="co"># 行和</span></a>
<a class="sourceLine" id="cb136-2" data-line-number="2">r &lt;-<span class="st"> </span><span class="kw">apply</span>(mat, <span class="dv">1</span>, sum)</a>
<a class="sourceLine" id="cb136-3" data-line-number="3"><span class="co"># 行最大值</span></a>
<a class="sourceLine" id="cb136-4" data-line-number="4">r &lt;-<span class="st"> </span><span class="kw">apply</span>(mat, <span class="dv">1</span>, max)</a>
<a class="sourceLine" id="cb136-5" data-line-number="5"><span class="co"># 行最小值</span></a>
<a class="sourceLine" id="cb136-6" data-line-number="6">r &lt;-<span class="st"> </span><span class="kw">apply</span>(mat, <span class="dv">1</span>, min)</a>
<a class="sourceLine" id="cb136-7" data-line-number="7"></a>
<a class="sourceLine" id="cb136-8" data-line-number="8"><span class="co"># 列和</span></a>
<a class="sourceLine" id="cb136-9" data-line-number="9">r &lt;-<span class="st"> </span><span class="kw">apply</span>(mat, <span class="dv">2</span>, sum)</a>
<a class="sourceLine" id="cb136-10" data-line-number="10"><span class="co"># 列最大值</span></a>
<a class="sourceLine" id="cb136-11" data-line-number="11">r &lt;-<span class="st"> </span><span class="kw">apply</span>(mat, <span class="dv">2</span>, max)</a>
<a class="sourceLine" id="cb136-12" data-line-number="12"><span class="co"># 列最小值</span></a>
<a class="sourceLine" id="cb136-13" data-line-number="13">r &lt;-<span class="st"> </span><span class="kw">apply</span>(mat, <span class="dv">2</span>, min)</a></code></pre></div>
<p>上面第 3 个参数传入的函数都是 R 内置的，我们完全可以传入自定义函数，这没有区别。</p>
<p>整体上看，<code>apply()</code> 非常得精简灵活。</p>
</div>
<div id="lapplysapply-和-vapply" class="section level5">
<h5><span class="header-section-number">2.3.4.2.2</span> lapply、sapply 和 vapply</h5>
<p><code>lapply()</code>、<code>sapply()</code> 和 <code>vapply()</code> 针对的都是列表结构的数据，<code>sapply()</code> 是简化版本的 <code>lapply()</code>，而 <code>vapply()</code> 则在 <code>sapply()</code> 的基础上加了结果验证，以保证可靠性。</p>
<p>我们假设有 4 组温度数据：</p>
<div class="sourceCode" id="cb137"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb137-1" data-line-number="1"><span class="kw">set.seed</span>(<span class="dv">1234</span>)</a>
<a class="sourceLine" id="cb137-2" data-line-number="2"></a>
<a class="sourceLine" id="cb137-3" data-line-number="3">temp &lt;-<span class="st"> </span><span class="kw">list</span>(</a>
<a class="sourceLine" id="cb137-4" data-line-number="4">  <span class="dv">35</span> <span class="op">+</span><span class="st"> </span><span class="kw">rnorm</span>(<span class="dv">10</span>, <span class="dt">mean =</span> <span class="dv">1</span>, <span class="dt">sd =</span> <span class="dv">10</span>),</a>
<a class="sourceLine" id="cb137-5" data-line-number="5">  <span class="dv">20</span> <span class="op">+</span><span class="st"> </span><span class="kw">rnorm</span>(<span class="dv">5</span>, <span class="dt">mean =</span> <span class="dv">1</span>, <span class="dt">sd =</span> <span class="dv">3</span>),</a>
<a class="sourceLine" id="cb137-6" data-line-number="6">  <span class="dv">25</span> <span class="op">+</span><span class="st"> </span><span class="kw">rnorm</span>(<span class="dv">22</span>, <span class="dt">mean =</span> <span class="dv">2</span>, <span class="dt">sd =</span> <span class="dv">6</span>),</a>
<a class="sourceLine" id="cb137-7" data-line-number="7">  <span class="dv">33</span> <span class="op">+</span><span class="st"> </span><span class="kw">rnorm</span>(<span class="dv">14</span>, <span class="dt">mean =</span> <span class="dv">4</span>, <span class="dt">sd =</span> <span class="dv">20</span>)</a>
<a class="sourceLine" id="cb137-8" data-line-number="8">)</a></code></pre></div>
<p>现在要求取每一组的温度最小、最大、平均值与中位数。我们针对列表的子集创建处理函数：</p>
<div class="sourceCode" id="cb138"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb138-1" data-line-number="1">basic &lt;-<span class="st"> </span><span class="cf">function</span>(x) {</a>
<a class="sourceLine" id="cb138-2" data-line-number="2">  <span class="kw">c</span>(<span class="dt">min =</span> <span class="kw">min</span>(x), <span class="dt">mean =</span> <span class="kw">mean</span>(x), <span class="dt">median =</span> <span class="kw">median</span>(x), <span class="dt">max =</span> <span class="kw">max</span>(x))</a>
<a class="sourceLine" id="cb138-3" data-line-number="3">}</a></code></pre></div>
<p>直接将列表数据、处理函数依次传入 <code>lapply()</code> 函数：</p>
<div class="sourceCode" id="cb139"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb139-1" data-line-number="1"><span class="kw">lapply</span>(temp, basic)</a>
<a class="sourceLine" id="cb139-2" data-line-number="2"><span class="co">#&gt; [[1]]</span></a>
<a class="sourceLine" id="cb139-3" data-line-number="3"><span class="co">#&gt;    min   mean median    max </span></a>
<a class="sourceLine" id="cb139-4" data-line-number="4"><span class="co">#&gt;  12.54  32.17  30.44  46.84 </span></a>
<a class="sourceLine" id="cb139-5" data-line-number="5"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb139-6" data-line-number="6"><span class="co">#&gt; [[2]]</span></a>
<a class="sourceLine" id="cb139-7" data-line-number="7"><span class="co">#&gt;    min   mean median    max </span></a>
<a class="sourceLine" id="cb139-8" data-line-number="8"><span class="co">#&gt;  18.00  20.26  19.57  23.88 </span></a>
<a class="sourceLine" id="cb139-9" data-line-number="9"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb139-10" data-line-number="10"><span class="co">#&gt; [[3]]</span></a>
<a class="sourceLine" id="cb139-11" data-line-number="11"><span class="co">#&gt;    min   mean median    max </span></a>
<a class="sourceLine" id="cb139-12" data-line-number="12"><span class="co">#&gt;  13.92  24.44  23.96  41.50 </span></a>
<a class="sourceLine" id="cb139-13" data-line-number="13"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb139-14" data-line-number="14"><span class="co">#&gt; [[4]]</span></a>
<a class="sourceLine" id="cb139-15" data-line-number="15"><span class="co">#&gt;     min    mean  median     max </span></a>
<a class="sourceLine" id="cb139-16" data-line-number="16"><span class="co">#&gt;  0.8794 22.7069 18.7612 65.9899</span></a></code></pre></div>
<p>虽然传入的列表子集不是等长的，但处理的结果却是等长的，因此上述输出看起来略显冗余。</p>
<p>因此我们使用 <code>sapply()</code> 进行简化，它的用法与 <code>lapply()</code> 相同，函数名中的 <code>s</code> 是简化（simplified）的首字母缩写。</p>
<div class="sourceCode" id="cb140"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb140-1" data-line-number="1"><span class="kw">sapply</span>(temp, basic)</a>
<a class="sourceLine" id="cb140-2" data-line-number="2"><span class="co">#&gt;         [,1]  [,2]  [,3]    [,4]</span></a>
<a class="sourceLine" id="cb140-3" data-line-number="3"><span class="co">#&gt; min    12.54 18.00 13.92  0.8794</span></a>
<a class="sourceLine" id="cb140-4" data-line-number="4"><span class="co">#&gt; mean   32.17 20.26 24.44 22.7069</span></a>
<a class="sourceLine" id="cb140-5" data-line-number="5"><span class="co">#&gt; median 30.44 19.57 23.96 18.7612</span></a>
<a class="sourceLine" id="cb140-6" data-line-number="6"><span class="co">#&gt; max    46.84 23.88 41.50 65.9899</span></a></code></pre></div>
<p>是不是更加紧凑？</p>
<p>我们再看一下 <code>vapply()</code>：</p>
<div class="sourceCode" id="cb141"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb141-1" data-line-number="1"><span class="kw">vapply</span>(temp, basic, <span class="kw">numeric</span>(<span class="dv">4</span>))</a>
<a class="sourceLine" id="cb141-2" data-line-number="2"><span class="co">#&gt;         [,1]  [,2]  [,3]    [,4]</span></a>
<a class="sourceLine" id="cb141-3" data-line-number="3"><span class="co">#&gt; min    12.54 18.00 13.92  0.8794</span></a>
<a class="sourceLine" id="cb141-4" data-line-number="4"><span class="co">#&gt; mean   32.17 20.26 24.44 22.7069</span></a>
<a class="sourceLine" id="cb141-5" data-line-number="5"><span class="co">#&gt; median 30.44 19.57 23.96 18.7612</span></a>
<a class="sourceLine" id="cb141-6" data-line-number="6"><span class="co">#&gt; max    46.84 23.88 41.50 65.9899</span></a></code></pre></div>
<p>结果与 <code>sapply()</code> 完全一致。<code>vapply()</code> 第 3 个参数传入对每一个子集调用函数后结果的预期，上述设定为包含 4 个元素的数值型向量。</p>
<p>如果与预期不一致，R 会抛出错误信息：</p>
<div class="sourceCode" id="cb142"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb142-1" data-line-number="1"><span class="kw">vapply</span>(temp, basic, <span class="kw">numeric</span>(<span class="dv">3</span>))</a>
<a class="sourceLine" id="cb142-2" data-line-number="2"><span class="co">#&gt; Error in vapply(temp, basic, numeric(3)): 值的长度必需为3，</span></a>
<a class="sourceLine" id="cb142-3" data-line-number="3"><span class="co">#&gt;  但FUN(X[[1]])结果的长度却是4</span></a></code></pre></div>
<p>apply 函数家族还有其他成员，如 <code>tapply()</code>，由于使用频率较低，这里就不再过多介绍。如果有需要，读者也能够基于上述知识轻松地通过 R 提供的代码示例进行快速学习和掌握。</p>
</div>
</div>
</div>
</div>
<div id="三方包的安装与加载" class="section level2">
<h2><span class="header-section-number">2.4</span> 三方包的安装与加载</h2>
<p>R 内置了基础计算、统计分析和绘图包，但依旧无法满足众多 R 用户的个性化需求。目前有超过 10,000 个三方包分布在 CRAN、Bioconductor、GitHub 等平台上，它们得安装方式都不尽相同。</p>
<div id="cran" class="section level3">
<h3><span class="header-section-number">2.4.1</span> CRAN</h3>
<p><a href="https://cran.r-project.org/">CRAN</a> 是由 R 核心团队维护的存档库，大多数的 R 包都发布在 CRAN 上。R 内置了安装命令 <code>install.packages()</code>。</p>
<p>下面是安装著名绘图包 <strong>ggplot2</strong> 的示例：</p>
<div class="sourceCode" id="cb143"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb143-1" data-line-number="1"><span class="kw">install.packages</span>(<span class="st">&quot;ggplot2&quot;</span>)</a></code></pre></div>
<p>本地的源码包也可以通过该命令安装，如安装我本地存有的 <strong>sigminer</strong> 包：</p>
<div class="sourceCode" id="cb144"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb144-1" data-line-number="1"><span class="kw">install.packages</span>(<span class="st">&quot;../sigminer_1.0.0.tar.gz&quot;</span>, <span class="dt">repos =</span> <span class="ot">NULL</span>)</a></code></pre></div>
<p>CRAN 默认使用国外镜像，国内的 R 用户下载包速度可能比较慢，推荐使用 <a href="https://mirrors.tuna.tsinghua.edu.cn/help/CRAN/">CRAN 清华源</a>。</p>
<p>先使用命令打开配置文件：</p>
<div class="sourceCode" id="cb145"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb145-1" data-line-number="1"><span class="kw">file.edit</span>(<span class="st">&quot;~/.Rprofile&quot;</span>)</a></code></pre></div>
<p>然后在该文档内追加内容：</p>
<div class="sourceCode" id="cb146"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb146-1" data-line-number="1"><span class="kw">options</span>(<span class="st">&quot;repos&quot;</span> =<span class="st"> </span><span class="kw">c</span>(<span class="dt">CRAN=</span><span class="st">&quot;https://mirrors.tuna.tsinghua.edu.cn/CRAN/&quot;</span>))</a></code></pre></div>
<p>保存后重启 R。</p>
</div>
<div id="bioconductor" class="section level3">
<h3><span class="header-section-number">2.4.2</span> Bioconductor</h3>
<p><a href="https://www.bioconductor.org/">Bioconductor</a> 是一个生物信息学项目，存储了上千个生物信息学领域相关的软件包、数据包和实验包等。安装 Bioconductor 上的包需要先安装 <strong>BiocManager</strong> 包：</p>
<div class="sourceCode" id="cb147"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb147-1" data-line-number="1"><span class="kw">install.packages</span>(<span class="st">&quot;BiocManager&quot;</span>)</a></code></pre></div>
<p>然后就可以使用 <code>install()</code> 函数安装 Bioconductor 上的包了，如 <strong>maftools</strong> ：</p>
<div class="sourceCode" id="cb148"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb148-1" data-line-number="1">BiocManager<span class="op">::</span><span class="kw">install</span>(<span class="st">&quot;maftools&quot;</span>)</a></code></pre></div>
<p>值得一提的是，该命令也可以安装 CRAN 上的包。</p>
<p>读者需要注意 Bioconductor 是有不同的版本的，这可以通过下面命令检查：</p>
<div class="sourceCode" id="cb149"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb149-1" data-line-number="1">BiocManager<span class="op">::</span><span class="kw">version</span>()</a>
<a class="sourceLine" id="cb149-2" data-line-number="2"><span class="co">#&gt; [1] &#39;3.11&#39;</span></a></code></pre></div>
<p>尽量保持版本处于最新状态可以获取相关包的最新特性和错误修复。</p>
<p>Bioconductor 默认使用国外镜像，国内的 R 用户下载包速度可能非常慢，推荐使用 <a href="https://mirrors.tuna.tsinghua.edu.cn/help/bioconductor/">Bioconductor 清华源</a>。</p>
<p>先使用命令打开配置文件：</p>
<div class="sourceCode" id="cb150"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb150-1" data-line-number="1"><span class="kw">file.edit</span>(<span class="st">&quot;~/.Rprofile&quot;</span>)</a></code></pre></div>
<p>然后在该文档内追加内容：</p>
<div class="sourceCode" id="cb151"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb151-1" data-line-number="1"><span class="kw">options</span>(<span class="dt">BioC_mirror=</span><span class="st">&quot;https://mirrors.tuna.tsinghua.edu.cn/bioconductor&quot;</span>)</a></code></pre></div>
<p>保存后重启 R。</p>
</div>
<div id="github-等-git-库" class="section level3">
<h3><span class="header-section-number">2.4.3</span> GitHub 等 Git 库</h3>
<p><a href="https://github.com/">GitHub</a> 是知名的开源软件库，上面存储了很多 R 包的源代码，包括 CRAN/Bioconductor 包、未发布包以及玩具包。只要有源代码有正确的 R 包框架，就可以通过 <strong>remotes</strong> 包安装。</p>
<p>例如，安装开发版本的 <strong>ggplot2</strong> 包：</p>
<div class="sourceCode" id="cb152"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb152-1" data-line-number="1">remotes<span class="op">::</span><span class="kw">install_github</span>(<span class="st">&quot;tidyverse/ggplot2&quot;</span>)</a></code></pre></div>
<p>也有其他对应函数安装其他的 Git 库包，如果 git 库还没有被支持（如中国的 gitee），可以使用 <code>remotes::install_git()</code> 安装。</p>
</div>
<div id="包使用" class="section level3">
<h3><span class="header-section-number">2.4.4</span> 包使用</h3>
<p>R 启动时默认加载的包可以通过 <code>.packages()</code> 命令获取：</p>
<div class="sourceCode" id="cb153"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb153-1" data-line-number="1"><span class="kw">print</span>(<span class="kw">.packages</span>())</a>
<a class="sourceLine" id="cb153-2" data-line-number="2"><span class="co">#&gt;  [1] &quot;readxl&quot;     &quot;data.table&quot; &quot;readr&quot;     </span></a>
<a class="sourceLine" id="cb153-3" data-line-number="3"><span class="co">#&gt;  [4] &quot;dplyr&quot;      &quot;ggplot2&quot;    &quot;stats&quot;     </span></a>
<a class="sourceLine" id="cb153-4" data-line-number="4"><span class="co">#&gt;  [7] &quot;graphics&quot;   &quot;grDevices&quot;  &quot;utils&quot;     </span></a>
<a class="sourceLine" id="cb153-5" data-line-number="5"><span class="co">#&gt; [10] &quot;datasets&quot;   &quot;methods&quot;    &quot;base&quot;</span></a></code></pre></div>
<p>由于在第 <a href="prepare.html#prepare">1</a> 章的配置一节中我有介绍使用 <strong>pacman</strong> 包作为第三方的包管理器，在 <code>~/.Rprofile</code> 中进行了设置，所以该包随着 R 的启动也被加载了。</p>
<p>整个 R 会话当前的所有信息都可以通过 <code>sessionInfo()</code> 获取，在向他人提问时提交该命令结果是一个良好的习惯。</p>
<div class="sourceCode" id="cb154"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb154-1" data-line-number="1"><span class="kw">sessionInfo</span>()</a>
<a class="sourceLine" id="cb154-2" data-line-number="2"><span class="co">#&gt; R version 4.0.0 (2020-04-24)</span></a>
<a class="sourceLine" id="cb154-3" data-line-number="3"><span class="co">#&gt; Platform: x86_64-apple-darwin17.0 (64-bit)</span></a>
<a class="sourceLine" id="cb154-4" data-line-number="4"><span class="co">#&gt; Running under: macOS Catalina 10.15.4</span></a>
<a class="sourceLine" id="cb154-5" data-line-number="5"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb154-6" data-line-number="6"><span class="co">#&gt; Matrix products: default</span></a>
<a class="sourceLine" id="cb154-7" data-line-number="7"><span class="co">#&gt; BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib</span></a>
<a class="sourceLine" id="cb154-8" data-line-number="8"><span class="co">#&gt; LAPACK: /Library/Frameworks/R.framework/Versions/4.0/Resources/lib/libRlapack.dylib</span></a>
<a class="sourceLine" id="cb154-9" data-line-number="9"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb154-10" data-line-number="10"><span class="co">#&gt; locale:</span></a>
<a class="sourceLine" id="cb154-11" data-line-number="11"><span class="co">#&gt; [1] zh_CN.UTF-8/zh_CN.UTF-8/zh_CN.UTF-8/C/zh_CN.UTF-8/zh_CN.UTF-8</span></a>
<a class="sourceLine" id="cb154-12" data-line-number="12"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb154-13" data-line-number="13"><span class="co">#&gt; attached base packages:</span></a>
<a class="sourceLine" id="cb154-14" data-line-number="14"><span class="co">#&gt; [1] stats     graphics  grDevices utils     datasets </span></a>
<a class="sourceLine" id="cb154-15" data-line-number="15"><span class="co">#&gt; [6] methods   base     </span></a>
<a class="sourceLine" id="cb154-16" data-line-number="16"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb154-17" data-line-number="17"><span class="co">#&gt; other attached packages:</span></a>
<a class="sourceLine" id="cb154-18" data-line-number="18"><span class="co">#&gt; [1] readxl_1.3.1      data.table_1.12.8</span></a>
<a class="sourceLine" id="cb154-19" data-line-number="19"><span class="co">#&gt; [3] readr_1.3.1       dplyr_0.8.5      </span></a>
<a class="sourceLine" id="cb154-20" data-line-number="20"><span class="co">#&gt; [5] ggplot2_3.3.0    </span></a>
<a class="sourceLine" id="cb154-21" data-line-number="21"><span class="co">#&gt; </span></a>
<a class="sourceLine" id="cb154-22" data-line-number="22"><span class="co">#&gt; loaded via a namespace (and not attached):</span></a>
<a class="sourceLine" id="cb154-23" data-line-number="23"><span class="co">#&gt;  [1] Rcpp_1.0.4.6        cellranger_1.1.0   </span></a>
<a class="sourceLine" id="cb154-24" data-line-number="24"><span class="co">#&gt;  [3] pillar_1.4.4        compiler_4.0.0     </span></a>
<a class="sourceLine" id="cb154-25" data-line-number="25"><span class="co">#&gt;  [5] BiocManager_1.30.10 highr_0.8          </span></a>
<a class="sourceLine" id="cb154-26" data-line-number="26"><span class="co">#&gt;  [7] tools_4.0.0         digest_0.6.25      </span></a>
<a class="sourceLine" id="cb154-27" data-line-number="27"><span class="co">#&gt;  [9] jsonlite_1.6.1      evaluate_0.14      </span></a>
<a class="sourceLine" id="cb154-28" data-line-number="28"><span class="co">#&gt; [11] lifecycle_0.2.0     tibble_3.0.1       </span></a>
<a class="sourceLine" id="cb154-29" data-line-number="29"><span class="co">#&gt; [13] gtable_0.3.0        pkgconfig_2.0.3    </span></a>
<a class="sourceLine" id="cb154-30" data-line-number="30"><span class="co">#&gt; [15] rlang_0.4.6         cli_2.0.2          </span></a>
<a class="sourceLine" id="cb154-31" data-line-number="31"><span class="co">#&gt; [17] rstudioapi_0.11     yaml_2.2.1         </span></a>
<a class="sourceLine" id="cb154-32" data-line-number="32"><span class="co">#&gt; [19] xfun_0.14           withr_2.2.0        </span></a>
<a class="sourceLine" id="cb154-33" data-line-number="33"><span class="co">#&gt; [21] stringr_1.4.0       knitr_1.28         </span></a>
<a class="sourceLine" id="cb154-34" data-line-number="34"><span class="co">#&gt; [23] vctrs_0.3.0         hms_0.5.3          </span></a>
<a class="sourceLine" id="cb154-35" data-line-number="35"><span class="co">#&gt; [25] grid_4.0.0          tidyselect_1.1.0   </span></a>
<a class="sourceLine" id="cb154-36" data-line-number="36"><span class="co">#&gt; [27] glue_1.4.1          R6_2.4.1           </span></a>
<a class="sourceLine" id="cb154-37" data-line-number="37"><span class="co">#&gt; [29] fansi_0.4.1         rmarkdown_2.1      </span></a>
<a class="sourceLine" id="cb154-38" data-line-number="38"><span class="co">#&gt; [31] bookdown_0.19       purrr_0.3.4        </span></a>
<a class="sourceLine" id="cb154-39" data-line-number="39"><span class="co">#&gt; [33] farver_2.0.3        magrittr_1.5       </span></a>
<a class="sourceLine" id="cb154-40" data-line-number="40"><span class="co">#&gt; [35] scales_1.1.1        ellipsis_0.3.1     </span></a>
<a class="sourceLine" id="cb154-41" data-line-number="41"><span class="co">#&gt; [37] htmltools_0.4.0     assertthat_0.2.1   </span></a>
<a class="sourceLine" id="cb154-42" data-line-number="42"><span class="co">#&gt; [39] colorspace_1.4-1    labeling_0.3       </span></a>
<a class="sourceLine" id="cb154-43" data-line-number="43"><span class="co">#&gt; [41] utf8_1.1.4          stringi_1.4.6      </span></a>
<a class="sourceLine" id="cb154-44" data-line-number="44"><span class="co">#&gt; [43] munsell_0.5.0       crayon_1.3.4</span></a></code></pre></div>
<div id="导入包" class="section level4">
<h4><span class="header-section-number">2.4.4.1</span> 导入包</h4>
<p>当我们需要导入（加载）一个包时，我们可以使用 <code>library()</code> 或 <code>require()</code> 函数。</p>
<div class="sourceCode" id="cb155"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb155-1" data-line-number="1"><span class="kw">library</span>(ggplot2)</a>
<a class="sourceLine" id="cb155-2" data-line-number="2"><span class="co"># 或</span></a>
<a class="sourceLine" id="cb155-3" data-line-number="3"><span class="kw">require</span>(ggplot2)</a></code></pre></div>
<p>两个函数的区别在于当 <code>library()</code> 导入一个本地不存在的 R 包时会报错，而 <code>require()</code> 会（隐式）返回为 <code>FALSE</code>，并抛出警告信息。</p>
<div class="sourceCode" id="cb156"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb156-1" data-line-number="1"><span class="kw">library</span>(zzzz)</a>
<a class="sourceLine" id="cb156-2" data-line-number="2"><span class="co">#&gt; Error in library(zzzz): 不存在叫&#39;zzzz&#39;这个名字的程辑包</span></a></code></pre></div>
<div class="sourceCode" id="cb157"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb157-1" data-line-number="1"><span class="kw">isFALSE</span>(<span class="kw">require</span>(zzzz))</a>
<a class="sourceLine" id="cb157-2" data-line-number="2"><span class="co">#&gt; Warning in library(package, lib.loc = lib.loc,</span></a>
<a class="sourceLine" id="cb157-3" data-line-number="3"><span class="co">#&gt; character.only = TRUE, logical.return = TRUE, : 不存在</span></a>
<a class="sourceLine" id="cb157-4" data-line-number="4"><span class="co">#&gt; 叫&#39;zzzz&#39;这个名字的程辑包</span></a>
<a class="sourceLine" id="cb157-5" data-line-number="5"><span class="co">#&gt; [1] TRUE</span></a></code></pre></div>
</div>
<div id="更新包" class="section level4">
<h4><span class="header-section-number">2.4.4.2</span> 更新包</h4>
<p>简单地更新包可以直接通过安装命令进行重装就可以了。</p>
<p>如果是更新所有的包，一个一个安装就未免太麻烦了，如果 R 不提示你，你也不知道有多少包可以更新。</p>
<p>R 默认有函数可以完成这项工作：</p>
<div class="sourceCode" id="cb158"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb158-1" data-line-number="1"><span class="kw">update.packages</span>()</a></code></pre></div>
<p>但这个函数需要读者不断点击确认，挺麻烦的。</p>
<p>下面推荐几个 3 方包提供的更新命令。</p>
<div class="sourceCode" id="cb159"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb159-1" data-line-number="1">pacman<span class="op">::</span><span class="kw">p_up</span>() <span class="co"># 或 pacman::p_update()</span></a>
<a class="sourceLine" id="cb159-2" data-line-number="2">BiocManager<span class="op">::</span><span class="kw">install</span>()</a>
<a class="sourceLine" id="cb159-3" data-line-number="3">rvcheck<span class="op">::</span><span class="kw">update_all</span>()</a>
<a class="sourceLine" id="cb159-4" data-line-number="4">remotes<span class="op">::</span><span class="kw">update_packages</span>()</a></code></pre></div>
<p>其中 <strong>rvcheck</strong> 是国内大名鼎鼎的 <a href="https://github.com/GuangchuangYu">Y 叔</a> 开发的，他有不少文章介绍该包，解决 R 包更新的一些痛点。</p>
</div>
<div id="使用包函数" class="section level4">
<h4><span class="header-section-number">2.4.4.3</span> 使用包函数</h4>
<p>R 包下载安装后其中函数的使用方法有两种，前面的例子都有涉及到，这里作一个简单介绍。</p>
<ol style="list-style-type: decimal">
<li>加载后使用</li>
</ol>
<p>这种方式适合读者需要用到一个包很多的函数，或者有的包需要利用加载过程同时载入它的依赖包，这时也必须加载后才能成功使用。加载后直接调用函数即可，下面是一个 <strong>ggplot2</strong> 包绘制散点图的例子：</p>
<div class="sourceCode" id="cb160"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb160-1" data-line-number="1"><span class="kw">library</span>(ggplot2)</a>
<a class="sourceLine" id="cb160-2" data-line-number="2"><span class="kw">qplot</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">10</span>, <span class="dv">1</span><span class="op">:</span><span class="dv">10</span>)</a></code></pre></div>
<div class="figure" style="text-align: center"><span id="fig:unnamed-chunk-148"></span>
<img src="bookdown_files/figure-html/unnamed-chunk-148-1.png" alt="一个 ggplot2 绘制的简单散点图" width="384" />
<p class="caption">
图 2.6: 一个 ggplot2 绘制的简单散点图
</p>
</div>
<ol start="2" style="list-style-type: decimal">
<li>直接使用</li>
</ol>
<p>这种方式适合只少量调用 R 包的函数，或者通过这种方式解决不同包存在同名函数问题。</p>
<div class="sourceCode" id="cb161"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb161-1" data-line-number="1"><span class="kw">library</span>(dplyr)</a></code></pre></div>
<p>上面我们载入 <strong>dplyr</strong> 包后，它屏蔽了 <strong>base</strong> 和 <strong>stats</strong> 包的一些同名函数。有的同名函数可能功能是一样的，不过做了一些拓展，所以使用起来没有问题。</p>
<p>下面是来自 <strong>base</strong> 包 <code>union()</code> 函数的示例代码：</p>
<div class="sourceCode" id="cb162"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb162-1" data-line-number="1">(x &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="kw">sort</span>(<span class="kw">sample</span>(<span class="dv">1</span><span class="op">:</span><span class="dv">20</span>, <span class="dv">9</span>)), <span class="ot">NA</span>))</a>
<a class="sourceLine" id="cb162-2" data-line-number="2"><span class="co">#&gt;  [1]  1  5  6  7  8 11 12 15 19 NA</span></a>
<a class="sourceLine" id="cb162-3" data-line-number="3">(y &lt;-<span class="st"> </span><span class="kw">c</span>(<span class="kw">sort</span>(<span class="kw">sample</span>(<span class="dv">3</span><span class="op">:</span><span class="dv">23</span>, <span class="dv">7</span>)), <span class="ot">NA</span>))</a>
<a class="sourceLine" id="cb162-4" data-line-number="4"><span class="co">#&gt; [1]  6  8 11 12 19 20 21 NA</span></a>
<a class="sourceLine" id="cb162-5" data-line-number="5"><span class="kw">union</span>(x, y)</a>
<a class="sourceLine" id="cb162-6" data-line-number="6"><span class="co">#&gt;  [1]  1  5  6  7  8 11 12 15 19 NA 20 21</span></a></code></pre></div>
<p>但有的函数就不一样了，如 <code>filter()</code> 函数。下面是来自 <strong>stats</strong> 包 <code>filter()</code> 函数的示例代码：</p>
<div class="sourceCode" id="cb163"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb163-1" data-line-number="1">x &lt;-<span class="st"> </span><span class="dv">1</span><span class="op">:</span><span class="dv">100</span></a>
<a class="sourceLine" id="cb163-2" data-line-number="2"><span class="kw">filter</span>(x, <span class="kw">rep</span>(<span class="dv">1</span>, <span class="dv">3</span>))</a>
<a class="sourceLine" id="cb163-3" data-line-number="3"><span class="co">#&gt; Error in UseMethod(&quot;filter_&quot;): &quot;filter_&quot;没有适用于&quot;c(&#39;integer&#39;, &#39;numeric&#39;)&quot;目标对象的方法</span></a></code></pre></div>
<p><code>filter()</code> 是一个数据分析过程中经常由于同名屏蔽出现问题的函数（因为 <strong>stats</strong> 包被 R 默认加载，而 <strong>dplyr</strong> 又是 R 用户常用的工具包，所以两者经常同时都被加载）。我们可以显式地调用 <strong>stats</strong> 包里的函数解决该问题：</p>
<div class="sourceCode" id="cb164"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb164-1" data-line-number="1">x &lt;-<span class="st"> </span><span class="dv">1</span><span class="op">:</span><span class="dv">100</span></a>
<a class="sourceLine" id="cb164-2" data-line-number="2">stats<span class="op">::</span><span class="kw">filter</span>(x, <span class="kw">rep</span>(<span class="dv">1</span>, <span class="dv">3</span>))</a>
<a class="sourceLine" id="cb164-3" data-line-number="3"><span class="co">#&gt; Time Series:</span></a>
<a class="sourceLine" id="cb164-4" data-line-number="4"><span class="co">#&gt; Start = 1 </span></a>
<a class="sourceLine" id="cb164-5" data-line-number="5"><span class="co">#&gt; End = 100 </span></a>
<a class="sourceLine" id="cb164-6" data-line-number="6"><span class="co">#&gt; Frequency = 1 </span></a>
<a class="sourceLine" id="cb164-7" data-line-number="7"><span class="co">#&gt;   [1]  NA   6   9  12  15  18  21  24  27  30  33  36</span></a>
<a class="sourceLine" id="cb164-8" data-line-number="8"><span class="co">#&gt;  [13]  39  42  45  48  51  54  57  60  63  66  69  72</span></a>
<a class="sourceLine" id="cb164-9" data-line-number="9"><span class="co">#&gt;  [25]  75  78  81  84  87  90  93  96  99 102 105 108</span></a>
<a class="sourceLine" id="cb164-10" data-line-number="10"><span class="co">#&gt;  [37] 111 114 117 120 123 126 129 132 135 138 141 144</span></a>
<a class="sourceLine" id="cb164-11" data-line-number="11"><span class="co">#&gt;  [49] 147 150 153 156 159 162 165 168 171 174 177 180</span></a>
<a class="sourceLine" id="cb164-12" data-line-number="12"><span class="co">#&gt;  [61] 183 186 189 192 195 198 201 204 207 210 213 216</span></a>
<a class="sourceLine" id="cb164-13" data-line-number="13"><span class="co">#&gt;  [73] 219 222 225 228 231 234 237 240 243 246 249 252</span></a>
<a class="sourceLine" id="cb164-14" data-line-number="14"><span class="co">#&gt;  [85] 255 258 261 264 267 270 273 276 279 282 285 288</span></a>
<a class="sourceLine" id="cb164-15" data-line-number="15"><span class="co">#&gt;  [97] 291 294 297  NA</span></a></code></pre></div>
<p>语法是 <code>包名::函数名</code>。</p>
</div>
</div>
</div>
<div id="编程实战roc-曲线计算与绘制" class="section level2">
<h2><span class="header-section-number">2.5</span> 编程实战：ROC 曲线计算与绘制</h2>
<p>本章的前几节内容涵盖了 R 初学者需要了解和掌握的基础编程知识，包括 R 内置数据结构的创建和使用、R 程序逻辑的控制。 读者在掌握这些内容后已经完全有能力去编写程序完成一些基本事务的处理。为了更好地帮助读者，本节我们通过一个实战项目来整合上述所有的知识点。</p>
<p>本节以数据科学中一个常见的二分类性能评估手段“ROC 曲线”作为目标，编写函数处理连续变量作为预测器时的 ROC 曲线定量和 AUC 计算。</p>
<p>我首先会简单介绍下相应的背景知识，然后呈现整个分析的实现代码，最后对整个过程进行讲解。</p>
<p>我建议读者在了解背景后独立思考如何实现，然后参考我提供的代码<strong>动手</strong>完成整个实现过程，接着浏览我对代码的讲解，重点深入阅读存疑的部分，反复思考，最后把整个项目从原理到实现完全掌握。</p>
<div id="背景与目标" class="section level3">
<h3><span class="header-section-number">2.5.1</span> 背景与目标</h3>
</div>
<div id="代码实现" class="section level3">
<h3><span class="header-section-number">2.5.2</span> 代码实现</h3>
</div>
<div id="代码讲解" class="section level3">
<h3><span class="header-section-number">2.5.3</span> 代码讲解</h3>
</div>
</div>
<div id="常见问题与方案-1" class="section level2">
<h2><span class="header-section-number">2.6</span> 常见问题与方案</h2>
<p>除了本节目前罗列的问题，读者在学习本章内容时遇到的其他问题都可以通过 <a href="https://github.com/ShixiangWang/geek-r-tutorial/issues">GitHub Issue</a> 提出和进行讨论。如果读者提出的是通性问题，将增补到该节。</p>
<div id="复数表示" class="section level3">
<h3><span class="header-section-number">2.6.1</span> 复数表示</h3>
<p>复数使用频次极少，但它也是一种 R 基础的数据类型。复数的表示方法与其他编程语言类似，使用 <code>i</code> 标定虚部。</p>
<p>例如：</p>
<div class="sourceCode" id="cb165"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb165-1" data-line-number="1"><span class="dv">1</span> <span class="op">+</span><span class="st"> </span>2i</a>
<a class="sourceLine" id="cb165-2" data-line-number="2"><span class="co">#&gt; [1] 1+2i</span></a></code></pre></div>
<p>运算符也可以针对复数使用，如：</p>
<div class="sourceCode" id="cb166"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb166-1" data-line-number="1">(<span class="dv">1</span> <span class="op">+</span><span class="st"> </span>2i)<span class="op">^</span><span class="dv">2</span></a>
<a class="sourceLine" id="cb166-2" data-line-number="2"><span class="co">#&gt; [1] -3+4i</span></a></code></pre></div>
</div>
<div id="与---的区别" class="section level3">
<h3><span class="header-section-number">2.6.2</span> = 与 &lt;- 的区别</h3>
<p>就我个人的使用而言，它的区别在调用函数时比较明显。</p>
<p>例如，计算程序运行时间：</p>
<div class="sourceCode" id="cb167"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb167-1" data-line-number="1"><span class="kw">system.time</span>(m &lt;-<span class="st"> </span><span class="kw">customMean</span>(<span class="dv">1</span><span class="op">:</span><span class="fl">1e6</span>))</a>
<a class="sourceLine" id="cb167-2" data-line-number="2"><span class="co">#&gt; 用户 系统 流逝 </span></a>
<a class="sourceLine" id="cb167-3" data-line-number="3"><span class="co">#&gt; 0.03 0.00 0.03</span></a></code></pre></div>
<p>下面的写法是错误的，因为 <code>system.time()</code> 把输入作为参数而不是一个表达式，而该函数并没有 <code>m</code> 这个参数。</p>
<div class="sourceCode" id="cb168"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb168-1" data-line-number="1"><span class="kw">system.time</span>(<span class="dt">m =</span> <span class="kw">customMean</span>(<span class="dv">1</span><span class="op">:</span><span class="fl">1e6</span>))</a>
<a class="sourceLine" id="cb168-2" data-line-number="2"><span class="co">#&gt; Error in system.time(m = customMean(1:1e+06)): 参数没有用(m = customMean(1:1e+06))</span></a></code></pre></div>
<p>例如，调用一个简单的函数时利用 <code>&lt;-</code> 传入参数：</p>
<div class="sourceCode" id="cb169"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb169-1" data-line-number="1">x &lt;-<span class="st"> </span><span class="ot">NULL</span></a>
<a class="sourceLine" id="cb169-2" data-line-number="2"><span class="kw">customMean</span>(x &lt;-<span class="st"> </span><span class="dv">1</span><span class="op">:</span><span class="dv">100</span>)</a>
<a class="sourceLine" id="cb169-3" data-line-number="3"><span class="co">#&gt; [1] 50.5</span></a>
<a class="sourceLine" id="cb169-4" data-line-number="4">x</a>
<a class="sourceLine" id="cb169-5" data-line-number="5"><span class="co">#&gt;   [1]   1   2   3   4   5   6   7   8   9  10  11  12</span></a>
<a class="sourceLine" id="cb169-6" data-line-number="6"><span class="co">#&gt;  [13]  13  14  15  16  17  18  19  20  21  22  23  24</span></a>
<a class="sourceLine" id="cb169-7" data-line-number="7"><span class="co">#&gt;  [25]  25  26  27  28  29  30  31  32  33  34  35  36</span></a>
<a class="sourceLine" id="cb169-8" data-line-number="8"><span class="co">#&gt;  [37]  37  38  39  40  41  42  43  44  45  46  47  48</span></a>
<a class="sourceLine" id="cb169-9" data-line-number="9"><span class="co">#&gt;  [49]  49  50  51  52  53  54  55  56  57  58  59  60</span></a>
<a class="sourceLine" id="cb169-10" data-line-number="10"><span class="co">#&gt;  [61]  61  62  63  64  65  66  67  68  69  70  71  72</span></a>
<a class="sourceLine" id="cb169-11" data-line-number="11"><span class="co">#&gt;  [73]  73  74  75  76  77  78  79  80  81  82  83  84</span></a>
<a class="sourceLine" id="cb169-12" data-line-number="12"><span class="co">#&gt;  [85]  85  86  87  88  89  90  91  92  93  94  95  96</span></a>
<a class="sourceLine" id="cb169-13" data-line-number="13"><span class="co">#&gt;  [97]  97  98  99 100</span></a></code></pre></div>
<p>这里先进行了赋值操作，然后才进行函数调用，所以 <code>x</code> 值被更改了。实际对函数传入参数时这种写法是不可取的。</p>
</div>
<div id="显式使用包函数时-与-的区别" class="section level3">
<h3><span class="header-section-number">2.6.3</span> 显式使用包函数时 :: 与 ::: 的区别</h3>
<p>R 包创建者可以选择哪些函数导出提出给用户使用，哪些是内部计算使用的或是处于开发试验阶段不提供外用。</p>
<p><code>::</code> 符号可以获取 R 包导出的函数，也是 R 包加载后可以使用的函数，如 <strong>ggplot2</strong> 包的 <code>qplot()</code> 函数。</p>
<p>而没有导出的函数则可以通过 <code>:::</code> 符号获取、调用。</p>
<p>例如 <strong>xfun</strong> 包的 <code>base_pkgs()</code> 函数。</p>
<div class="sourceCode" id="cb170"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb170-1" data-line-number="1">xfun<span class="op">:::</span><span class="kw">base_pkgs</span>()</a>
<a class="sourceLine" id="cb170-2" data-line-number="2"><span class="co">#&gt;  [1] &quot;base&quot;      &quot;compiler&quot;  &quot;datasets&quot;  &quot;graphics&quot; </span></a>
<a class="sourceLine" id="cb170-3" data-line-number="3"><span class="co">#&gt;  [5] &quot;grDevices&quot; &quot;grid&quot;      &quot;methods&quot;   &quot;parallel&quot; </span></a>
<a class="sourceLine" id="cb170-4" data-line-number="4"><span class="co">#&gt;  [9] &quot;splines&quot;   &quot;stats&quot;     &quot;stats4&quot;    &quot;tcltk&quot;    </span></a>
<a class="sourceLine" id="cb170-5" data-line-number="5"><span class="co">#&gt; [13] &quot;tools&quot;     &quot;utils&quot;</span></a></code></pre></div>
<p>下面的方式是错误的：</p>
<div class="sourceCode" id="cb171"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb171-1" data-line-number="1">xfun<span class="op">::</span><span class="kw">base_pkgs</span>()</a>
<a class="sourceLine" id="cb171-2" data-line-number="2"><span class="co">#&gt; Error: &#39;base_pkgs&#39;不是&#39;namespace:xfun&#39;内的出口对象：</span></a></code></pre></div>
<p>一般而言，除非你确信你知道这个函数对你有用，且知道如何使用它，否则不建议通过 <code>:::</code> 调用 R 包的不开放函数。</p>
</div>
<div id="因子重构" class="section level3">
<h3><span class="header-section-number">2.6.4</span> 因子重构</h3>
<p>如果我们向变量 <code>sex</code> 扩充两个 <code>M</code>，可能会遇到不能理解的结果：</p>
<div class="sourceCode" id="cb172"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb172-1" data-line-number="1">sex &lt;-<span class="st"> </span><span class="kw">factor</span>(<span class="kw">c</span>(<span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Male&quot;</span>))</a>
<a class="sourceLine" id="cb172-2" data-line-number="2">sex &lt;-<span class="st"> </span><span class="kw">c</span>(sex, <span class="kw">c</span>(<span class="st">&quot;M&quot;</span>, <span class="st">&quot;M&quot;</span>))</a>
<a class="sourceLine" id="cb172-3" data-line-number="3">sex</a>
<a class="sourceLine" id="cb172-4" data-line-number="4"><span class="co">#&gt; [1] &quot;2&quot; &quot;1&quot; &quot;1&quot; &quot;2&quot; &quot;2&quot; &quot;M&quot; &quot;M&quot;</span></a></code></pre></div>
<p>根本原因在于，当我们创建因子后，因子本身存储的实际内容已经被替换为了正整数，分类信息被存储到了水平中，正整数与分类产生的映射对依旧可以保存原本的信息。</p>
<div class="sourceCode" id="cb173"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb173-1" data-line-number="1">sex &lt;-<span class="st"> </span><span class="kw">factor</span>(<span class="kw">c</span>(<span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Female&quot;</span>, <span class="st">&quot;Male&quot;</span>, <span class="st">&quot;Male&quot;</span>))</a>
<a class="sourceLine" id="cb173-2" data-line-number="2"><span class="kw">str</span>(sex)</a>
<a class="sourceLine" id="cb173-3" data-line-number="3"><span class="co">#&gt;  Factor w/ 2 levels &quot;Female&quot;,&quot;Male&quot;: 2 1 1 2 2</span></a></code></pre></div>
<p>这样做的好处是节省内存开销，并有利于模型计算：</p>
<ul>
<li>当存在大量字符串时，R 依然只有少量的正整数即可表示。</li>
<li>数学模型并不支持字符串，当将因子纳入统计模型中时，实际上参与计算的是对应的正整数。</li>
</ul>
<p>解决上述问题的一个办法是先将 <code>sex</code> 转换回字符串，然后再创建因子。</p>
<div class="sourceCode" id="cb174"><pre class="sourceCode r"><code class="sourceCode r"><a class="sourceLine" id="cb174-1" data-line-number="1">sex &lt;-<span class="st"> </span><span class="kw">factor</span>(<span class="kw">c</span>(<span class="kw">as.character</span>(sex), <span class="st">&quot;M&quot;</span>, <span class="st">&quot;M&quot;</span>))</a>
<a class="sourceLine" id="cb174-2" data-line-number="2">sex</a>
<a class="sourceLine" id="cb174-3" data-line-number="3"><span class="co">#&gt; [1] Male   Female Female Male   Male   M      M     </span></a>
<a class="sourceLine" id="cb174-4" data-line-number="4"><span class="co">#&gt; Levels: Female M Male</span></a></code></pre></div>
</div>
<div id="理解-r-计算" class="section level3">
<h3><span class="header-section-number">2.6.5</span> 理解 R 计算</h3>
<ul>
<li>一切皆是对象。</li>
<li>一切皆是函数调用。</li>
</ul>

<p class="flushright">
John Chambers
</p>


</div>
</div>
</div>
            </section>

          </div>
        </div>
      </div>
<a href="prepare.html" class="navigation navigation-prev " aria-label="Previous page"><i class="fa fa-angle-left"></i></a>
<a href="import.html" class="navigation navigation-next " aria-label="Next page"><i class="fa fa-angle-right"></i></a>
    </div>
  </div>
<script src="libs/gitbook/js/app.min.js"></script>
<script src="libs/gitbook/js/lunr.js"></script>
<script src="libs/gitbook/js/clipboard.min.js"></script>
<script src="libs/gitbook/js/plugin-search.js"></script>
<script src="libs/gitbook/js/plugin-sharing.js"></script>
<script src="libs/gitbook/js/plugin-fontsettings.js"></script>
<script src="libs/gitbook/js/plugin-bookdown.js"></script>
<script src="libs/gitbook/js/jquery.highlight.js"></script>
<script src="libs/gitbook/js/plugin-clipboard.js"></script>
<script>
gitbook.require(["gitbook"], function(gitbook) {
gitbook.start({
"sharing": {
"github": true,
"facebook": true,
"twitter": true,
"linkedin": false,
"weibo": false,
"instapaper": false,
"vk": false,
"all": ["facebook", "twitter", "linkedin", "weibo", "instapaper"]
},
"fontsettings": {
"theme": "white",
"family": "sans",
"size": 2
},
"edit": {
"link": "https://github.com/ShixiangWang/geek-r-tutorial/edit/master/02-base.Rmd",
"text": "编辑"
},
"history": {
"link": null,
"text": null
},
"view": {
"link": null,
"text": null
},
"download": null,
"toc": {
"collapse": "section"
}
});
});
</script>

<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
  (function () {
    var script = document.createElement("script");
    script.type = "text/javascript";
    var src = "true";
    if (src === "" || src === "true") src = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-MML-AM_CHTML";
    if (location.protocol !== "file:")
      if (/^https?:/.test(src))
        src = src.replace(/^https?:/, '');
    script.src = src;
    document.getElementsByTagName("head")[0].appendChild(script);
  })();
</script>
</body>

</html>
